rpm 5.2.1

rpmio/iosm.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 <ugid.h>               /* XXX unameToUid() and gnameToGid() */
00011 
00012 #include <rpmsq.h>              /* XXX rpmsqJoin()/rpmsqThread() */
00013 #include <rpmsw.h>              /* XXX rpmswAdd() */
00014 
00015 #include "../rpmdb/rpmtag.h"
00016 
00017 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmts_s * rpmts;
00018 typedef /*@abstract@*/ struct rpmte_s * rpmte;
00019 
00020 #define _IOSM_INTERNAL
00021 #include <iosm.h>
00022 #define iosmUNSAFE      iosmStage
00023 
00024 #include "cpio.h"
00025 #include "tar.h"
00026 #include "ar.h"
00027 
00028 typedef iosmMapFlags cpioMapFlags;
00029 #define _RPMFI_INTERNAL
00030 #define _RPMFI_NOMETHODS
00031 #include "../lib/rpmfi.h"
00032 
00033 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmds_s * rpmds;
00034 typedef struct rpmRelocation_s * rpmRelocation;
00035 #undef  _USE_RPMTE
00036 #if defined(_USE_RPMTE)
00037 typedef /*@abstract@*/ void * alKey;
00038 #include "rpmte.h"
00039 #endif
00040 
00041 #undef  _USE_RPMSX
00042 #if defined(_USE_RPMSX)
00043 #include "../lib/rpmsx.h"               /* XXX rpmsx rpmsxFContext rpmsxFree */
00044 #endif
00045 
00046 typedef /*@abstract@*/ /*@refcounted@*/ struct rpmdb_s * rpmdb;
00047 typedef /*@abstract@*/ struct rpmmi_s * rpmmi;
00048 typedef struct rpmPRCO_s * rpmPRCO;
00049 typedef struct Spec_s * Spec;
00050 #undef  _USE_RPMTS
00051 #if defined(_USE_RPMTS)
00052 #include "rpmts.h"
00053 #endif
00054 
00055 #include "debug.h"
00056 
00057 /*@access FD_t @*/      /* XXX void ptr args */
00058 /*@access IOSMI_t @*/
00059 /*@access IOSM_t @*/
00060 
00061 /*@access rpmfi @*/
00062 
00063 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
00064 
00065 #define _IOSM_DEBUG     0
00066 /*@unchecked@*/
00067 int _iosm_debug = _IOSM_DEBUG;
00068 
00069 /*@-exportheadervar@*/
00070 /*@unchecked@*/
00071 int _iosm_threads = 0;
00072 /*@=exportheadervar@*/
00073 
00074 /*@-redecl@*/
00075 int (*_iosmNext) (IOSM_t iosm, iosmFileStage nstage)
00076         /*@modifies iosm @*/ = &iosmNext;
00077 /*@=redecl@*/
00078 
00079 #if defined(_USE_RPMTS)
00080 void * iosmGetTs(const IOSM_t iosm)
00081 {
00082     const IOSMI_t iter = iosm->iter;
00083     /*@-compdef -refcounttrans -retexpose -usereleased @*/
00084     return (iter ? iter->ts : NULL);
00085     /*@=compdef =refcounttrans =retexpose =usereleased @*/
00086 }
00087 #endif
00088 
00089 void * iosmGetFi(const IOSM_t iosm)
00090 {
00091     const IOSMI_t iter = iosm->iter;
00092     /*@-compdef -refcounttrans -retexpose -usereleased @*/
00093     return (iter ? iter->fi : NULL);
00094     /*@=compdef =refcounttrans =retexpose =usereleased @*/
00095 }
00096 
00097 #define SUFFIX_RPMORIG  ".rpmorig"
00098 #define SUFFIX_RPMSAVE  ".rpmsave"
00099 #define SUFFIX_RPMNEW   ".rpmnew"
00100 
00109 static /*@only@*//*@null@*/
00110 const char * iosmFsPath(/*@special@*/ /*@null@*/ const IOSM_t iosm,
00111                 /*@null@*/ const struct stat * st,
00112                 /*@null@*/ const char * subdir,
00113                 /*@null@*/ const char * suffix)
00114         /*@uses iosm->dirName, iosm->baseName */
00115         /*@*/
00116 {
00117     const char * s = NULL;
00118 
00119     if (iosm) {
00120         char * t;
00121         int nb;
00122         nb = strlen(iosm->dirName) +
00123             (st && !S_ISDIR(st->st_mode) ? (subdir ? strlen(subdir) : 0) : 0) +
00124             (st && !S_ISDIR(st->st_mode) ? (suffix ? strlen(suffix) : 0) : 0) +
00125             strlen(iosm->baseName) + 1;
00126         s = t = xmalloc(nb);
00127         t = stpcpy(t, iosm->dirName);
00128         if (st && !S_ISDIR(st->st_mode))
00129             if (subdir) t = stpcpy(t, subdir);
00130         t = stpcpy(t, iosm->baseName);
00131         if (st && !S_ISDIR(st->st_mode))
00132             if (suffix) t = stpcpy(t, suffix);
00133     }
00134     return s;
00135 }
00136 
00142 static /*@null@*/ void * mapFreeIterator(/*@only@*//*@null@*/ void * p)
00143         /*@modifies p @*/
00144 {
00145     IOSMI_t iter = p;
00146     if (iter) {
00147 #if !defined(_RPMFI_NOMETHODS)
00148         iter->fi = rpmfiUnlink(iter->fi, "mapIterator");
00149 #endif
00150         iter->fi = NULL;
00151     }
00152     return _free(p);
00153 }
00154 
00161 /*@-mustmod@*/
00162 static void *
00163 mapInitIterator(rpmfi fi, int reverse)
00164         /*@modifies fi @*/
00165 {
00166     IOSMI_t iter = NULL;
00167 
00168     iter = xcalloc(1, sizeof(*iter));
00169 #if !defined(_RPMFI_NOMETHODS)
00170     iter->fi = rpmfiLink(fi, "mapIterator");
00171 #else
00172 /*@i@*/ iter->fi = fi;
00173 #endif
00174     iter->reverse = reverse;
00175     iter->i = (iter->reverse ? (fi->fc - 1) : 0);
00176     iter->isave = iter->i;
00177     return iter;
00178 }
00179 /*@=mustmod@*/
00180 
00186 static int mapNextIterator(/*@null@*/ void * a)
00187         /*@*/
00188 {
00189     IOSMI_t iter = a;
00190     int i = -1;
00191 
00192     if (iter) {
00193         if (iter->reverse) {
00194             if (iter->i >= 0)   i = iter->i--;
00195         } else {
00196             if (iter->i < (int) ((rpmfi)iter->fi)->fc)  i = iter->i++;
00197         }
00198         iter->isave = i;
00199     }
00200     return i;
00201 }
00202 
00205 static int iosmStrCmp(const void * a, const void * b)
00206         /*@*/
00207 {
00208     const char * aurl = *(const char **)a;
00209     const char * burl = *(const char **)b;
00210     const char * afn = NULL;
00211     const char * bfn = NULL;
00212 
00213     (void) urlPath(aurl, &afn);
00214     (void) urlPath(burl, &bfn);
00215 
00216 #ifdef  VERY_OLD_BUGGY_RPM_PACKAGES
00217     /* XXX Some rpm-2.4 packages from 1997 have basename only in payloads. */
00218     if (strchr(afn, '/') == NULL)
00219         bfn = strrchr(bfn, '/') + 1;
00220 #endif
00221 
00222     /* Match rpm-4.0 payloads with ./ prefixes. */
00223     if (afn[0] == '.' && afn[1] == '/') afn += 2;
00224     if (bfn[0] == '.' && bfn[1] == '/') bfn += 2;
00225 
00226     /* If either path is absolute, make it relative to '/'. */
00227     if (afn[0] == '/')  afn += 1;
00228     if (bfn[0] == '/')  bfn += 1;
00229 
00230     return strcmp(afn, bfn);
00231 }
00232 
00239 static int mapFind(/*@null@*/ IOSMI_t iter, const char * iosmPath)
00240         /*@modifies iter @*/
00241 {
00242     int ix = -1;
00243 
00244     if (iter) {
00245 /*@-onlytrans@*/
00246         const rpmfi fi = iter->fi;
00247 /*@=onlytrans@*/
00248 #if !defined(_RPMFI_NOMETHODS)
00249         size_t fc = rpmfiFC(fi);
00250 #else
00251         size_t fc = (fi ? fi->fc : 0);
00252 #endif
00253         if (fi && fc > 0 && fi->apath && iosmPath && *iosmPath) {
00254             const char ** p = NULL;
00255 
00256             if (fi->apath != NULL)
00257                 p = bsearch(&iosmPath, fi->apath, fc, sizeof(iosmPath),
00258                         iosmStrCmp);
00259             if (p) {
00260                 iter->i = p - fi->apath;
00261                 ix = mapNextIterator(iter);
00262             }
00263         }
00264     }
00265     return ix;
00266 }
00267 
00271 typedef struct dnli_s {
00272     rpmfi fi;
00273 /*@only@*/ /*@null@*/
00274     char * active;
00275     int reverse;
00276     int isave;
00277     int i;
00278 } * DNLI_t;
00279 
00285 static /*@null@*/ void * dnlFreeIterator(/*@only@*//*@null@*/ const void * a)
00286         /*@modifies a @*/
00287 {
00288     if (a) {
00289         DNLI_t dnli = (void *)a;
00290         if (dnli->active) free(dnli->active);
00291     }
00292     return _free(a);
00293 }
00294 
00297 static inline int dnlCount(/*@null@*/ const DNLI_t dnli)
00298         /*@*/
00299 {
00300     return (int) (dnli ? dnli->fi->dc : 0);
00301 }
00302 
00305 static inline int dnlIndex(/*@null@*/ const DNLI_t dnli)
00306         /*@*/
00307 {
00308     return (dnli ? dnli->isave : -1);
00309 }
00310 
00317 /*@-usereleased@*/
00318 static /*@only@*/ /*@null@*/
00319 void * dnlInitIterator(/*@special@*/ const IOSM_t iosm,
00320                 int reverse)
00321         /*@uses iosm->iter @*/ 
00322         /*@*/
00323 {
00324     rpmfi fi = iosmGetFi(iosm);
00325     const char * dnl;
00326     DNLI_t dnli;
00327     int i, j;
00328 
00329     if (fi == NULL)
00330         return NULL;
00331     dnli = xcalloc(1, sizeof(*dnli));
00332     dnli->fi = fi;
00333     dnli->reverse = reverse;
00334     dnli->i = (int) (reverse ? fi->dc : 0);
00335 
00336     if (fi->dc) {
00337         dnli->active = xcalloc(fi->dc, sizeof(*dnli->active));
00338 
00339         /* Identify parent directories not skipped. */
00340 #if !defined(_RPMFI_NOMETHODS)
00341         if ((fi = rpmfiInit(fi, 0)) != NULL)
00342         while ((i = rpmfiNext(fi)) >= 0)
00343 #else
00344         for (i = 0; i < (int)fi->fc; i++)
00345 #endif
00346         {
00347             if (!iosmFileActionSkipped(fi->actions[i]))
00348                 dnli->active[fi->dil[i]] = (char)1;
00349         }
00350 
00351         /* Exclude parent directories that are explicitly included. */
00352 #if !defined(_RPMFI_NOMETHODS)
00353         if ((fi = rpmfiInit(fi, 0)) != NULL)
00354         while ((i = rpmfiNext(fi)) >= 0)
00355 #else
00356         for (i = 0; i < (int)fi->fc; i++)
00357 #endif
00358         {
00359             rpmuint32_t dil;
00360             size_t dnlen, bnlen;
00361 
00362             if (!S_ISDIR(fi->fmodes[i]))
00363                 continue;
00364 
00365             dil = fi->dil[i];
00366             dnlen = strlen(fi->dnl[dil]);
00367             bnlen = strlen(fi->bnl[i]);
00368 
00369             for (j = 0; j < (int)fi->dc; j++) {
00370                 size_t jlen;
00371 
00372                 if (!dnli->active[j] || j == (int)dil)
00373                     /*@innercontinue@*/ continue;
00374                 (void) urlPath(fi->dnl[j], &dnl);
00375                 jlen = strlen(dnl);
00376                 if (jlen != (dnlen+bnlen+1))
00377                     /*@innercontinue@*/ continue;
00378                 if (strncmp(dnl, fi->dnl[dil], dnlen))
00379                     /*@innercontinue@*/ continue;
00380                 if (strncmp(dnl+dnlen, fi->bnl[i], bnlen))
00381                     /*@innercontinue@*/ continue;
00382                 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
00383                     /*@innercontinue@*/ continue;
00384                 /* This directory is included in the package. */
00385                 dnli->active[j] = (char)0;
00386                 /*@innerbreak@*/ break;
00387             }
00388         }
00389 
00390         /* Print only once per package. */
00391         if (!reverse) {
00392             j = 0;
00393             for (i = 0; i < (int)fi->dc; i++) {
00394                 if (!dnli->active[i]) continue;
00395                 if (j == 0) {
00396                     j = 1;
00397                     rpmlog(RPMLOG_DEBUG,
00398         D_("========== Directories not explicitly included in package:\n"));
00399                 }
00400                 (void) urlPath(fi->dnl[i], &dnl);
00401                 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, dnl);
00402             }
00403             if (j)
00404                 rpmlog(RPMLOG_DEBUG, "==========\n");
00405         }
00406     }
00407     return dnli;
00408 }
00409 /*@=usereleased@*/
00410 
00416 static /*@observer@*/ /*@null@*/
00417 const char * dnlNextIterator(/*@null@*/ DNLI_t dnli)
00418         /*@modifies dnli @*/
00419 {
00420     const char * dn = NULL;
00421 
00422     if (dnli) {
00423         rpmfi fi = dnli->fi;
00424         int i = -1;
00425 
00426         if (dnli->active)
00427         do {
00428             i = (!dnli->reverse ? dnli->i++ : --dnli->i);
00429         } while (i >= 0 && i < (int)fi->dc && !dnli->active[i]);
00430 
00431         if (i >= 0 && i < (int)fi->dc)
00432             dn = fi->dnl[i];
00433         else
00434             i = -1;
00435         dnli->isave = i;
00436     }
00437     return dn;
00438 }
00439 
00440 #if defined(WITH_PTHREADS)
00441 static void * iosmThread(void * arg)
00442         /*@globals h_errno, fileSystem, internalState @*/
00443         /*@modifies arg, fileSystem, internalState @*/
00444 {
00445     IOSM_t iosm = arg;
00446 /*@-unqualifiedtrans@*/
00447     return ((void *) ((long)iosmStage(iosm, iosm->nstage)));
00448 /*@=unqualifiedtrans@*/
00449 }
00450 #endif
00451 
00452 int iosmNext(IOSM_t iosm, iosmFileStage nstage)
00453         /*@globals h_errno, fileSystem, internalState @*/
00454         /*@modifies iosm, fileSystem, internalState @*/
00455 {
00456     iosm->nstage = nstage;
00457 #if defined(WITH_PTHREADS)
00458     if (iosm->multithreaded)
00459         return rpmsqJoin( rpmsqThread(iosmThread, iosm) );
00460 #endif
00461     return iosmStage(iosm, iosm->nstage);
00462 }
00463 
00469 static int saveHardLink(/*@special@*/ /*@partial@*/ IOSM_t iosm)
00470         /*@uses iosm->links, iosm->ix, iosm->sb, iosm->goal, iosm->nsuffix @*/
00471         /*@defines iosm->li @*/
00472         /*@releases iosm->path @*/
00473         /*@globals h_errno, fileSystem, internalState @*/
00474         /*@modifies iosm, fileSystem, internalState @*/
00475 {
00476     struct stat * st = &iosm->sb;
00477     int rc = 0;
00478     int ix = -1;
00479     int j;
00480 
00481     /* Find hard link set. */
00482     for (iosm->li = iosm->links; iosm->li; iosm->li = iosm->li->next) {
00483         if (iosm->li->sb.st_ino == st->st_ino && iosm->li->sb.st_dev == st->st_dev)
00484             break;
00485     }
00486 
00487     /* New hard link encountered, add new link to set. */
00488     if (iosm->li == NULL) {
00489         iosm->li = xcalloc(1, sizeof(*iosm->li));
00490         iosm->li->next = NULL;
00491         iosm->li->sb = *st;     /* structure assignment */
00492         iosm->li->nlink = (int) st->st_nlink;
00493         iosm->li->linkIndex = iosm->ix;
00494         iosm->li->createdPath = -1;
00495 
00496         iosm->li->filex = xcalloc(st->st_nlink, sizeof(iosm->li->filex[0]));
00497         memset(iosm->li->filex, -1, (st->st_nlink * sizeof(iosm->li->filex[0])));
00498         iosm->li->nsuffix = xcalloc(st->st_nlink, sizeof(*iosm->li->nsuffix));
00499 
00500         if (iosm->goal == IOSM_PKGBUILD)
00501             iosm->li->linksLeft = (int) st->st_nlink;
00502         if (iosm->goal == IOSM_PKGINSTALL)
00503             iosm->li->linksLeft = 0;
00504 
00505         /*@-kepttrans@*/
00506         iosm->li->next = iosm->links;
00507         /*@=kepttrans@*/
00508         iosm->links = iosm->li;
00509     }
00510 
00511     if (iosm->goal == IOSM_PKGBUILD) --iosm->li->linksLeft;
00512     iosm->li->filex[iosm->li->linksLeft] = iosm->ix;
00513     /*@-observertrans -dependenttrans@*/
00514     iosm->li->nsuffix[iosm->li->linksLeft] = iosm->nsuffix;
00515     /*@=observertrans =dependenttrans@*/
00516     if (iosm->goal == IOSM_PKGINSTALL) iosm->li->linksLeft++;
00517 
00518     if (iosm->goal == IOSM_PKGBUILD)
00519         return (iosm->li->linksLeft > 0);
00520 
00521     if (iosm->goal != IOSM_PKGINSTALL)
00522         return 0;
00523 
00524     if (!(st->st_size || iosm->li->linksLeft == (int) st->st_nlink))
00525         return 1;
00526 
00527     /* Here come the bits, time to choose a non-skipped file name. */
00528     {   rpmfi fi = iosmGetFi(iosm);
00529 
00530         for (j = iosm->li->linksLeft - 1; j >= 0; j--) {
00531             ix = iosm->li->filex[j];
00532             if (ix < 0 || iosmFileActionSkipped(fi->actions[ix]))
00533                 continue;
00534             break;
00535         }
00536     }
00537 
00538     /* Are all links skipped or not encountered yet? */
00539     if (ix < 0 || j < 0)
00540         return 1;       /* XXX W2DO? */
00541 
00542     /* Save the non-skipped file name and map index. */
00543     iosm->li->linkIndex = j;
00544     iosm->path = _free(iosm->path);
00545     iosm->ix = ix;
00546     rc = iosmNext(iosm, IOSM_MAP);
00547     return rc;
00548 }
00549 
00555 static /*@null@*/ void * freeHardLink(/*@only@*/ /*@null@*/ struct hardLink_s * li)
00556         /*@modifies li @*/
00557 {
00558     if (li) {
00559         li->nsuffix = _free(li->nsuffix);       /* XXX elements are shared */
00560         li->filex = _free(li->filex);
00561     }
00562     return _free(li);
00563 }
00564 
00565 IOSM_t newIOSM(void)
00566 {
00567     IOSM_t iosm = xcalloc(1, sizeof(*iosm));
00568     return iosm;
00569 }
00570 
00571 IOSM_t freeIOSM(IOSM_t iosm)
00572 {
00573     if (iosm) {
00574         iosm->path = _free(iosm->path);
00575         while ((iosm->li = iosm->links) != NULL) {
00576             iosm->links = iosm->li->next;
00577             iosm->li->next = NULL;
00578             iosm->li = freeHardLink(iosm->li);
00579         }
00580         iosm->dnlx = _free(iosm->dnlx);
00581         iosm->ldn = _free(iosm->ldn);
00582         iosm->iter = mapFreeIterator(iosm->iter);
00583     }
00584     return _free(iosm);
00585 }
00586 
00587 static int arSetup(IOSM_t iosm, rpmfi fi)
00588         /*@modifies iosm @*/
00589 {
00590     const char * path;
00591     char * t;
00592     size_t lmtablen = 0;
00593     size_t nb;
00594 
00595     /* Calculate size of ar(1) long member table. */
00596 #if !defined(_RPMFI_NOMETHODS)
00597     if ((fi = rpmfiInit(fi, 0)) != NULL)
00598     while (rpmfiNext(fi) >= 0)
00599 #else
00600     int i;
00601     if (fi != NULL)
00602     for (i = 0; i < (int)fi->fc; i++)
00603 #endif
00604     {
00605 #ifdef  NOTYET
00606         if (fi->apath) {
00607             const char * apath = NULL;
00608             (void) urlPath(fi->apath[ix], &apath);
00609             path = apath + fi->striplen;
00610         } else
00611 #endif
00612 #if !defined(_RPMFI_NOMETHODS)
00613             path = rpmfiBN(fi);
00614 #else
00615             path = fi->bnl[i];
00616 #endif
00617         if ((nb = strlen(path)) < 15)
00618             continue;
00619         lmtablen += nb + 1;     /* trailing \n */
00620     }
00621 
00622     /* Anything to do? */
00623     if (lmtablen == 0)
00624         return 0;
00625 
00626     /* Create and load ar(1) long member table. */
00627     iosm->lmtab = t = xmalloc(lmtablen + 1);    /* trailing \0 */
00628     iosm->lmtablen = lmtablen;
00629     iosm->lmtaboff = 0;
00630 #if !defined(_RPMFI_NOMETHODS)
00631     if ((fi = rpmfiInit(fi, 0)) != NULL)
00632     while (rpmfiNext(fi) >= 0)
00633 #else
00634     if (fi != NULL)
00635     for (i = 0; i < (int)fi->fc; i++)
00636 #endif
00637     {
00638 #ifdef  NOTYET
00639         if (fi->apath) {
00640             const char * apath = NULL;
00641             (void) urlPath(fi->apath[ix], &apath);
00642             path = apath + fi->striplen;
00643         } else
00644 #endif
00645 #if !defined(_RPMFI_NOMETHODS)
00646             path = rpmfiBN(fi);
00647 #else
00648             path = fi->bnl[i];
00649 #endif
00650         if ((nb = strlen(path)) < 15)
00651             continue;
00652         t = stpcpy(t, path);
00653         *t++ = '\n';
00654     }
00655     *t = '\0';
00656     
00657     return 0;
00658 }
00659 
00660 int iosmSetup(IOSM_t iosm, iosmFileStage goal, const char * afmt,
00661                 const void * _ts, const void * _fi, FD_t cfd,
00662                 unsigned int * archiveSize, const char ** failedFile)
00663 {
00664 #if defined(_USE_RPMTS)
00665     const rpmts ts = (const rpmts) _ts;
00666 #endif
00667 /*@i@*/ const rpmfi fi = (const rpmfi) _fi;
00668 #if defined(_USE_RPMTE)
00669     int reverse = (rpmteType(fi->te) == TR_REMOVED && fi->action != FA_COPYOUT);
00670     int adding = (rpmteType(fi->te) == TR_ADDED);
00671 #else
00672     int reverse = 0;    /* XXX HACK: devise alternative means */
00673     int adding = 1;     /* XXX HACK: devise alternative means */
00674 #endif
00675     size_t pos = 0;
00676     int rc, ec = 0;
00677 
00678     iosm->debug = _iosm_debug;
00679     iosm->multithreaded = _iosm_threads;
00680     iosm->adding = adding;
00681 
00682 /*@+voidabstract -nullpass@*/
00683 if (iosm->debug < 0)
00684 fprintf(stderr, "--> iosmSetup(%p, 0x%x, \"%s\", %p, %p, %p, %p, %p)\n", iosm, goal, afmt, (void *)_ts, _fi, cfd, archiveSize, failedFile);
00685 /*@=voidabstract =nullpass@*/
00686 
00687     _iosmNext = &iosmNext;
00688     if (iosm->headerRead == NULL) {
00689         if (afmt != NULL && (!strcmp(afmt, "tar") || !strcmp(afmt, "ustar"))) {
00690 if (iosm->debug < 0)
00691 fprintf(stderr, "\ttar vectors set\n");
00692             iosm->headerRead = &tarHeaderRead;
00693             iosm->headerWrite = &tarHeaderWrite;
00694             iosm->trailerWrite = &tarTrailerWrite;
00695             iosm->blksize = TAR_BLOCK_SIZE;
00696         } else
00697         if (afmt != NULL && !strcmp(afmt, "ar")) {
00698 if (iosm->debug < 0)
00699 fprintf(stderr, "\tar vectors set\n");
00700             iosm->headerRead = &arHeaderRead;
00701             iosm->headerWrite = &arHeaderWrite;
00702             iosm->trailerWrite = &arTrailerWrite;
00703             iosm->blksize = 2;
00704             if (goal == IOSM_PKGBUILD || goal == IOSM_PKGERASE)
00705                 (void) arSetup(iosm, fi);
00706         } else
00707         {
00708 if (iosm->debug < 0)
00709 fprintf(stderr, "\tcpio vectors set\n");
00710             iosm->headerRead = &cpioHeaderRead;
00711             iosm->headerWrite = &cpioHeaderWrite;
00712             iosm->trailerWrite = &cpioTrailerWrite;
00713             iosm->blksize = 4;
00714         }
00715     }
00716 
00717     iosm->goal = goal;
00718     if (cfd != NULL) {
00719 /*@-assignexpose@*/
00720         iosm->cfd = fdLink(cfd, "persist (iosm)");
00721 /*@=assignexpose@*/
00722         pos = fdGetCpioPos(iosm->cfd);
00723         fdSetCpioPos(iosm->cfd, 0);
00724     }
00725 /*@-mods@*/     /* WTF? */
00726     iosm->iter = mapInitIterator(fi, reverse);
00727 /*@=mods@*/
00728 #if defined(_USE_RPMTS)
00729     iosm->iter->ts = rpmtsLink(ts, "mapIterator");
00730     iosm->nofcontexts = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS);
00731     iosm->nofdigests =
00732         (ts != NULL && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOFDIGESTS))
00733                         ? 0 : 1;
00734 #define _tsmask (RPMTRANS_FLAG_PKGCOMMIT | RPMTRANS_FLAG_COMMIT)
00735     iosm->commit = ((ts && (rpmtsFlags(ts) & _tsmask) &&
00736                         iosm->goal != IOSM_PKGCOMMIT) ? 0 : 1);
00737 #undef _tsmask
00738 #else
00739 /*@-assignexpose -temptrans @*/
00740     iosm->iter->ts = (void *)_ts;
00741 /*@=assignexpose =temptrans @*/
00742     iosm->nofcontexts = 1;
00743     iosm->nofdigests = 1;
00744     iosm->commit = 1;
00745 #endif
00746 
00747     if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
00748         fi->archivePos = 0;
00749 #if defined(_USE_RPMTS)
00750         (void) rpmtsNotify(ts, fi->te,
00751                 RPMCALLBACK_INST_START, fi->archivePos, fi->archiveSize);
00752 #endif
00753     }
00754 
00755     /*@-assignexpose@*/
00756     iosm->archiveSize = archiveSize;
00757     if (iosm->archiveSize)
00758         *iosm->archiveSize = 0;
00759     iosm->failedFile = failedFile;
00760     if (iosm->failedFile)
00761         *iosm->failedFile = NULL;
00762     /*@=assignexpose@*/
00763 
00764     memset(iosm->sufbuf, 0, sizeof(iosm->sufbuf));
00765     if (iosm->goal == IOSM_PKGINSTALL) {
00766         rpmuint32_t tid;
00767 #if defined(_USE_RPMTS)
00768         tid = (ts != NULL ? rpmtsGetTid(ts) : 0);
00769 #else
00770         static time_t now = 0;
00771         if (now == 0) now = time(NULL);
00772         tid = (rpmuint32_t) now;
00773 #endif
00774         if (tid > 0 && tid < 0xffffffff)
00775             sprintf(iosm->sufbuf, ";%08x", (unsigned)tid);
00776     }
00777 
00778     ec = iosm->rc = 0;
00779     rc = iosmUNSAFE(iosm, IOSM_CREATE);
00780     if (rc && !ec) ec = rc;
00781 
00782     rc = iosmUNSAFE(iosm, iosm->goal);
00783     if (rc && !ec) ec = rc;
00784 
00785     if (iosm->archiveSize && ec == 0)
00786         *iosm->archiveSize = (fdGetCpioPos(iosm->cfd) - pos);
00787 
00788 /*@-nullstate@*/ /* FIX: *iosm->failedFile may be NULL */
00789    return ec;
00790 /*@=nullstate@*/
00791 }
00792 
00793 int iosmTeardown(IOSM_t iosm)
00794 {
00795     int rc = iosm->rc;
00796 
00797 if (iosm->debug < 0)
00798 fprintf(stderr, "--> iosmTeardown(%p)\n", iosm);
00799     if (!rc)
00800         rc = iosmUNSAFE(iosm, IOSM_DESTROY);
00801 
00802     iosm->lmtab = _free(iosm->lmtab);
00803 
00804 #if defined(_USE_RPMTS)
00805     (void) rpmswAdd(rpmtsOp(iosmGetTs(iosm), RPMTS_OP_DIGEST),
00806                         &iosm->op_digest);
00807     (void)rpmtsFree(iter->ts); 
00808     iter->ts = NULL;
00809 #else
00810     iosm->iter->ts = NULL;
00811 #endif
00812     iosm->iter = mapFreeIterator(iosm->iter);
00813     if (iosm->cfd != NULL) {
00814         iosm->cfd = fdFree(iosm->cfd, "persist (iosm)");
00815         iosm->cfd = NULL;
00816     }
00817     iosm->failedFile = NULL;
00818     return rc;
00819 }
00820 
00821 /*
00822  * Set file security context (if not disabled).
00823  * @param iosm          file state machine data
00824  * @return              0 always
00825  */
00826 static int iosmMapFContext(IOSM_t iosm)
00827         /*@modifies iosm @*/
00828 {
00829     /*
00830      * Find file security context (if not disabled).
00831      */
00832     iosm->fcontext = NULL;
00833     if (!iosm->nofcontexts) {
00834         security_context_t scon = NULL;
00835         int xx = matchpathcon(iosm->path, iosm->sb.st_mode, &scon);
00836 
00837 /*@-moduncon@*/
00838         if (!xx && scon != NULL)
00839             iosm->fcontext = scon;
00840 #ifdef  DYING   /* XXX SELinux file contexts not set from package content. */
00841         else {
00842             rpmfi fi = iosmGetFi(iosm);
00843             int i = iosm->ix;
00844 
00845             /* Get file security context from package. */
00846             if (fi && i >= 0 && i < (int)fi->fc)
00847                 iosm->fcontext = (fi->fcontexts ? fi->fcontexts[i] : NULL);
00848         }
00849 #endif
00850 /*@=moduncon@*/
00851     }
00852     return 0;
00853 }
00854 
00855 int iosmMapPath(IOSM_t iosm)
00856 {
00857     rpmfi fi = iosmGetFi(iosm); /* XXX const except for fstates */
00858     int teAdding = iosm->adding;
00859     int rc = 0;
00860     int i = iosm->ix;
00861 
00862     iosm->osuffix = NULL;
00863     iosm->nsuffix = NULL;
00864     iosm->astriplen = 0;
00865     iosm->action = FA_UNKNOWN;
00866     iosm->mapFlags = fi->mapflags;
00867 
00868     if (fi && i >= 0 && i < (int)fi->fc) {
00869 
00870         iosm->astriplen = fi->astriplen;
00871         iosm->action = (fi->actions ? fi->actions[i] : fi->action);
00872         iosm->fflags = (fi->fflags ? fi->fflags[i] : fi->flags);
00873         iosm->mapFlags = (fi->fmapflags ? fi->fmapflags[i] : fi->mapflags);
00874 
00875         /* src rpms have simple base name in payload. */
00876         iosm->dirName = fi->dnl[fi->dil[i]];
00877         iosm->baseName = fi->bnl[i];
00878 
00879         switch (iosm->action) {
00880         case FA_SKIP:
00881             break;
00882         case FA_UNKNOWN:
00883             break;
00884 
00885         case FA_COPYOUT:
00886             break;
00887         case FA_COPYIN:
00888         case FA_CREATE:
00889 assert(teAdding);
00890             break;
00891 
00892         case FA_SKIPNSTATE:
00893             if (fi->fstates && teAdding)
00894                 fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_NOTINSTALLED;
00895             break;
00896 
00897         case FA_SKIPNETSHARED:
00898             if (fi->fstates && teAdding)
00899                 fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_NETSHARED;
00900             break;
00901 
00902         case FA_SKIPCOLOR:
00903             if (fi->fstates && teAdding)
00904                 fi->fstates[i] = (rpmuint8_t)RPMFILE_STATE_WRONGCOLOR;
00905             break;
00906 
00907         case FA_BACKUP:
00908             if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00909                 iosm->osuffix = (teAdding ? SUFFIX_RPMORIG : SUFFIX_RPMSAVE);
00910             break;
00911 
00912         case FA_ALTNAME:
00913 assert(teAdding);
00914             if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00915                 iosm->nsuffix = SUFFIX_RPMNEW;
00916             break;
00917 
00918         case FA_SAVE:
00919 assert(teAdding);
00920             if (!(iosm->fflags & RPMFILE_GHOST)) /* XXX Don't if %ghost file. */
00921                 iosm->osuffix = SUFFIX_RPMSAVE;
00922             break;
00923         case FA_ERASE:
00924 #if 0   /* XXX is this a genhdlist fix? */
00925             assert(rpmteType(fi->te) == TR_REMOVED);
00926 #endif
00927             /*
00928              * XXX TODO: %ghost probably shouldn't be removed, but that changes
00929              * legacy rpm behavior.
00930              */
00931             break;
00932         default:
00933             break;
00934         }
00935 
00936         if ((iosm->mapFlags & IOSM_MAP_PATH) || iosm->nsuffix) {
00937             const struct stat * st = &iosm->sb;
00938             iosm->path = _free(iosm->path);
00939             iosm->path = iosmFsPath(iosm, st, iosm->subdir,
00940                 (iosm->suffix ? iosm->suffix : iosm->nsuffix));
00941         }
00942     }
00943     return rc;
00944 }
00945 
00946 int iosmMapAttrs(IOSM_t iosm)
00947 {
00948     struct stat * st = &iosm->sb;
00949     rpmfi fi = iosmGetFi(iosm);
00950     int i = iosm->ix;
00951 
00952     if (fi && i >= 0 && i < (int)fi->fc) {
00953         mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
00954         mode_t finalMode = (fi->fmodes ? (mode_t)fi->fmodes[i] : perms);
00955         dev_t finalRdev = (fi->frdevs ? fi->frdevs[i] : 0);
00956         rpmuint32_t finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
00957         uid_t uid = fi->uid;
00958         gid_t gid = fi->gid;
00959 
00960 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00961         /* Make sure OpenPKG/Mandriva RPM does not try to set file owner/group on files during
00962            installation of _source_ RPMs. Instead, let it use the current
00963            run-time owner/group, because most of the time the owner/group in
00964            the source RPM (which is the owner/group of the files as staying on
00965            the package author system) is not existing on the target system, of
00966            course. */
00967 #endif
00968         if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
00969 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00970           if (!fi->isSource) {
00971 #endif
00972             if (iosm->goal == IOSM_PKGINSTALL)
00973                 rpmlog(RPMLOG_WARNING,
00974                     _("user %s does not exist - using root\n"), fi->fuser[i]);
00975             uid = 0;
00976             finalMode &= ~S_ISUID;      /* turn off suid bit */
00977 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00978           }
00979 #endif
00980         }
00981 
00982         if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
00983 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00984           if (!fi->isSource) {
00985 #endif
00986             if (iosm->goal == IOSM_PKGINSTALL)
00987                 rpmlog(RPMLOG_WARNING,
00988                     _("group %s does not exist - using root\n"), fi->fgroup[i]);
00989             gid = 0;
00990             finalMode &= ~S_ISGID;      /* turn off sgid bit */
00991 #if defined(RPM_VENDOR_OPENPKG) || defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* no-owner-group-on-srpm-install */
00992           }
00993 #endif
00994         }
00995 
00996         if (iosm->mapFlags & IOSM_MAP_MODE)
00997             st->st_mode = (st->st_mode & S_IFMT) | (finalMode & ~S_IFMT);
00998         if (iosm->mapFlags & IOSM_MAP_TYPE) {
00999             st->st_mode = (st->st_mode & ~S_IFMT) | (finalMode & S_IFMT);
01000             if ((S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
01001             && st->st_nlink == 0)
01002                 st->st_nlink = 1;
01003             st->st_rdev = finalRdev;
01004             st->st_mtime = finalMtime;
01005         }
01006         if (iosm->mapFlags & IOSM_MAP_UID)
01007             st->st_uid = uid;
01008         if (iosm->mapFlags & IOSM_MAP_GID)
01009             st->st_gid = gid;
01010 
01011         /*
01012          * Set file digest (if not disabled).
01013          */
01014         if (!iosm->nofdigests) {
01015             iosm->fdigestalgo = fi->digestalgo;
01016             iosm->fdigest = (fi->fdigests ? fi->fdigests[i] : NULL);
01017             iosm->digestlen = fi->digestlen;
01018             iosm->digest = (fi->digests ? (fi->digests + (iosm->digestlen * i)) : NULL);
01019         } else {
01020             iosm->fdigestalgo = 0;
01021             iosm->fdigest = NULL;
01022             iosm->digestlen = 0;
01023             iosm->digest = NULL;
01024         }
01025     }
01026     return 0;
01027 }
01028 
01034 /*@-compdef@*/
01035 static int extractRegular(/*@special@*/ IOSM_t iosm)
01036         /*@uses iosm->fdigest, iosm->digest, iosm->sb, iosm->wfd  @*/
01037         /*@globals h_errno, fileSystem, internalState @*/
01038         /*@modifies iosm, fileSystem, internalState @*/
01039 {
01040     const struct stat * st = &iosm->sb;
01041     size_t left = (size_t) st->st_size;
01042     int rc = 0;
01043     int xx;
01044 
01045     rc = iosmNext(iosm, IOSM_WOPEN);
01046     if (rc)
01047         goto exit;
01048 
01049     if (st->st_size > 0 && (iosm->fdigest != NULL || iosm->digest != NULL))
01050         fdInitDigest(iosm->wfd, iosm->fdigestalgo, 0);
01051 
01052     while (left) {
01053 
01054         iosm->wrlen = (left > iosm->wrsize ? iosm->wrsize : left);
01055         rc = iosmNext(iosm, IOSM_DREAD);
01056         if (rc)
01057             goto exit;
01058 
01059         rc = iosmNext(iosm, IOSM_WRITE);
01060         if (rc)
01061             goto exit;
01062 
01063         left -= iosm->wrnb;
01064 
01065         /* Notify iff progress, completion is done elsewhere */
01066         if (!rc && left)
01067             (void) iosmNext(iosm, IOSM_NOTIFY);
01068     }
01069 
01070     xx = fsync(Fileno(iosm->wfd));
01071 
01072     if (st->st_size > 0 && (iosm->fdigest || iosm->digest)) {
01073         void * digest = NULL;
01074         int asAscii = (iosm->digest == NULL ? 1 : 0);
01075 
01076         (void) Fflush(iosm->wfd);
01077         fdFiniDigest(iosm->wfd, iosm->fdigestalgo, &digest, NULL, asAscii);
01078 
01079         if (digest == NULL) {
01080             rc = IOSMERR_DIGEST_MISMATCH;
01081             goto exit;
01082         }
01083 
01084         if (iosm->digest != NULL) {
01085             if (memcmp(digest, iosm->digest, iosm->digestlen))
01086                 rc = IOSMERR_DIGEST_MISMATCH;
01087         } else {
01088             if (strcmp(digest, iosm->fdigest))
01089                 rc = IOSMERR_DIGEST_MISMATCH;
01090         }
01091         digest = _free(digest);
01092     }
01093 
01094 exit:
01095     (void) iosmNext(iosm, IOSM_WCLOSE);
01096     return rc;
01097 }
01098 /*@=compdef@*/
01099 
01106 /*@-compdef -compmempass@*/
01107 static int writeFile(/*@special@*/ /*@partial@*/ IOSM_t iosm, int writeData)
01108         /*@uses iosm->path, iosm->opath, iosm->sb, iosm->osb, iosm->cfd @*/
01109         /*@globals h_errno, fileSystem, internalState @*/
01110         /*@modifies iosm, fileSystem, internalState @*/
01111 {
01112     const char * path = iosm->path;
01113     const char * opath = iosm->opath;
01114     struct stat * st = &iosm->sb;
01115     struct stat * ost = &iosm->osb;
01116     size_t left;
01117     int xx;
01118     int rc;
01119 
01120     st->st_size = (writeData ? ost->st_size : 0);
01121 
01122     if (S_ISDIR(st->st_mode)) {
01123         st->st_size = 0;
01124     } else if (S_ISLNK(st->st_mode)) {
01125         /*
01126          * While linux puts the size of a symlink in the st_size field,
01127          * I don't think that's a specified standard.
01128          */
01129         /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */
01130         rc = iosmUNSAFE(iosm, IOSM_READLINK);
01131         if (rc) goto exit;
01132         st->st_size = iosm->rdnb;
01133         iosm->lpath = xstrdup(iosm->rdbuf);     /* XXX save readlink return. */
01134     }
01135 
01136     if (iosm->mapFlags & IOSM_MAP_ABSOLUTE) {
01137         size_t nb=strlen(iosm->dirName) + strlen(iosm->baseName) + sizeof(".");
01138         char * t = alloca(nb);
01139         *t = '\0';
01140         iosm->path = t;
01141         if (iosm->mapFlags & IOSM_MAP_ADDDOT)
01142             *t++ = '.';
01143         t = stpcpy( stpcpy(t, iosm->dirName), iosm->baseName);
01144     } else if (iosm->mapFlags & IOSM_MAP_PATH) {
01145         rpmfi fi = iosmGetFi(iosm);
01146         if (fi->apath) {
01147             const char * apath = NULL;
01148             (void) urlPath(fi->apath[iosm->ix], &apath);
01149             iosm->path = apath + fi->striplen;
01150         } else
01151             iosm->path = fi->bnl[iosm->ix];
01152     }
01153 
01154     rc = iosmNext(iosm, IOSM_HWRITE);
01155     iosm->path = path;
01156     if (rc) goto exit;
01157 
01158     if (writeData && S_ISREG(st->st_mode)) {
01159 #if defined(HAVE_MMAP)
01160         char * rdbuf = NULL;
01161         void * mapped = (void *)-1;
01162         size_t nmapped = 0;
01163         /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
01164         int use_mmap = (st->st_size <= 0x07ffffff);
01165 #endif
01166 
01167         rc = iosmNext(iosm, IOSM_ROPEN);
01168         if (rc) goto exit;
01169 
01170         /* XXX unbuffered mmap generates *lots* of fdio debugging */
01171 #if defined(HAVE_MMAP)
01172         if (use_mmap) {
01173             mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(iosm->rfd), 0);
01174             if (mapped != (void *)-1) {
01175                 rdbuf = iosm->rdbuf;
01176                 iosm->rdbuf = (char *) mapped;
01177                 iosm->rdlen = nmapped = st->st_size;
01178 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
01179                 xx = madvise(mapped, nmapped, MADV_DONTNEED);
01180 #endif
01181             }
01182         }
01183 #endif
01184 
01185         left = st->st_size;
01186 
01187         while (left) {
01188 #if defined(HAVE_MMAP)
01189           if (mapped != (void *)-1) {
01190             iosm->rdnb = nmapped;
01191           } else
01192 #endif
01193           {
01194             iosm->rdlen = (left > iosm->rdsize ? iosm->rdsize : left),
01195             rc = iosmNext(iosm, IOSM_READ);
01196             if (rc) goto exit;
01197           }
01198 
01199             /* XXX DWRITE uses rdnb for I/O length. */
01200             rc = iosmNext(iosm, IOSM_DWRITE);
01201             if (rc) goto exit;
01202 
01203             left -= iosm->wrnb;
01204         }
01205 
01206 #if defined(HAVE_MMAP)
01207         if (mapped != (void *)-1) {
01208 /* XXX splint misses size_t 2nd arg. */
01209 /*@i@*/     xx = msync(mapped, nmapped, MS_ASYNC);
01210 #if defined(HAVE_MADVISE) && defined(MADV_DONTNEED)
01211             xx = madvise(mapped, nmapped, MADV_DONTNEED);
01212 #endif
01213             xx = munmap(mapped, nmapped);
01214             iosm->rdbuf = rdbuf;
01215         } else
01216 #endif
01217             xx = fsync(Fileno(iosm->rfd));
01218 
01219     }
01220 
01221     rc = iosmNext(iosm, IOSM_PAD);
01222     if (rc) goto exit;
01223 
01224     rc = 0;
01225 
01226 exit:
01227     if (iosm->rfd != NULL)
01228         (void) iosmNext(iosm, IOSM_RCLOSE);
01229 /*@-dependenttrans@*/
01230     iosm->opath = opath;
01231     iosm->path = path;
01232 /*@=dependenttrans@*/
01233     return rc;
01234 }
01235 /*@=compdef =compmempass@*/
01236 
01242 static int writeLinkedFile(/*@special@*/ /*@partial@*/ IOSM_t iosm)
01243         /*@uses iosm->path, iosm->nsuffix, iosm->ix, iosm->li, iosm->failedFile @*/
01244         /*@globals h_errno, fileSystem, internalState @*/
01245         /*@modifies iosm, fileSystem, internalState @*/
01246 {
01247     const char * path = iosm->path;
01248     const char * lpath = iosm->lpath;
01249     const char * nsuffix = iosm->nsuffix;
01250     int iterIndex = iosm->ix;
01251     int ec = 0;
01252     int rc;
01253     int i;
01254     const char * linkpath = NULL;
01255     int firstfile = 1;
01256 
01257     iosm->path = NULL;
01258     iosm->lpath = NULL;
01259     iosm->nsuffix = NULL;
01260     iosm->ix = -1;
01261 
01262     for (i = iosm->li->nlink - 1; i >= 0; i--) {
01263 
01264         if (iosm->li->filex[i] < 0) continue;
01265 
01266         iosm->ix = iosm->li->filex[i];
01267 /*@-compdef@*/
01268         rc = iosmNext(iosm, IOSM_MAP);
01269 /*@=compdef@*/
01270 
01271         /* XXX tar and cpio have to do things differently. */
01272         if (iosm->headerWrite == tarHeaderWrite) {
01273             if (firstfile) {
01274                 const char * apath = NULL;
01275                 char *t;
01276                 (void) urlPath(iosm->path, &apath);
01277                 /* Remove the buildroot prefix. */
01278                 t = xmalloc(sizeof(".") + strlen(apath + iosm->astriplen));
01279                 (void) stpcpy( stpcpy(t, "."), apath + iosm->astriplen);
01280                 linkpath = t;
01281                 firstfile = 0;
01282             } else
01283                 iosm->lpath = linkpath;
01284 
01285             /* Write data after first link for tar. */
01286             rc = writeFile(iosm, (iosm->lpath == NULL));
01287         } else {
01288             /* Write data after last link for cpio. */
01289             rc = writeFile(iosm, (i == 0));
01290         }
01291         if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) {
01292             ec = rc;
01293             *iosm->failedFile = xstrdup(iosm->path);
01294         }
01295 
01296         iosm->path = _free(iosm->path);
01297         iosm->li->filex[i] = -1;
01298     }
01299 
01300 /*@-dependenttrans@*/
01301     linkpath = _free(linkpath);
01302 /*@=dependenttrans@*/
01303     iosm->ix = iterIndex;
01304     iosm->nsuffix = nsuffix;
01305     iosm->lpath = lpath;
01306     iosm->path = path;
01307     return ec;
01308 }
01309 
01315 /*@-compdef@*/
01316 static int iosmMakeLinks(/*@special@*/ /*@partial@*/ IOSM_t iosm)
01317         /*@uses iosm->path, iosm->opath, iosm->nsuffix, iosm->ix, iosm->li @*/
01318         /*@globals h_errno, fileSystem, internalState @*/
01319         /*@modifies iosm, fileSystem, internalState @*/
01320 {
01321     const char * path = iosm->path;
01322     const char * opath = iosm->opath;
01323     const char * nsuffix = iosm->nsuffix;
01324     int iterIndex = iosm->ix;
01325     int ec = 0;
01326     int rc;
01327     int i;
01328 
01329     iosm->path = NULL;
01330     iosm->opath = NULL;
01331     iosm->nsuffix = NULL;
01332     iosm->ix = -1;
01333 
01334     iosm->ix = iosm->li->filex[iosm->li->createdPath];
01335     rc = iosmNext(iosm, IOSM_MAP);
01336     iosm->opath = iosm->path;
01337     iosm->path = NULL;
01338     for (i = 0; i < iosm->li->nlink; i++) {
01339         if (iosm->li->filex[i] < 0) continue;
01340         if (iosm->li->createdPath == i) continue;
01341 
01342         iosm->ix = iosm->li->filex[i];
01343         iosm->path = _free(iosm->path);
01344         rc = iosmNext(iosm, IOSM_MAP);
01345         if (iosmFileActionSkipped(iosm->action)) continue;
01346 
01347         rc = iosmUNSAFE(iosm, IOSM_VERIFY);
01348         if (!rc) continue;
01349         if (!(rc == IOSMERR_ENOENT)) break;
01350 
01351         /* XXX link(iosm->opath, iosm->path) */
01352         rc = iosmNext(iosm, IOSM_LINK);
01353         if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) {
01354             ec = rc;
01355             *iosm->failedFile = xstrdup(iosm->path);
01356         }
01357 
01358         iosm->li->linksLeft--;
01359     }
01360     iosm->path = _free(iosm->path);
01361     iosm->opath = _free(iosm->opath);
01362 
01363     iosm->ix = iterIndex;
01364     iosm->nsuffix = nsuffix;
01365     iosm->path = path;
01366     iosm->opath = opath;
01367     return ec;
01368 }
01369 /*@=compdef@*/
01370 
01376 /*@-compdef@*/
01377 static int iosmCommitLinks(/*@special@*/ /*@partial@*/ IOSM_t iosm)
01378         /*@uses iosm->path, iosm->nsuffix, iosm->ix, iosm->sb,
01379                 iosm->li, iosm->links @*/
01380         /*@globals h_errno, fileSystem, internalState @*/
01381         /*@modifies iosm, fileSystem, internalState @*/
01382 {
01383     const char * path = iosm->path;
01384     const char * nsuffix = iosm->nsuffix;
01385     int iterIndex = iosm->ix;
01386     struct stat * st = &iosm->sb;
01387     int rc = 0;
01388     int i;
01389 
01390     iosm->path = NULL;
01391     iosm->nsuffix = NULL;
01392     iosm->ix = -1;
01393 
01394     for (iosm->li = iosm->links; iosm->li; iosm->li = iosm->li->next) {
01395         if (iosm->li->sb.st_ino == st->st_ino && iosm->li->sb.st_dev == st->st_dev)
01396             break;
01397     }
01398 
01399     for (i = 0; i < iosm->li->nlink; i++) {
01400         if (iosm->li->filex[i] < 0) continue;
01401         iosm->ix = iosm->li->filex[i];
01402         rc = iosmNext(iosm, IOSM_MAP);
01403         if (!iosmFileActionSkipped(iosm->action))
01404             rc = iosmNext(iosm, IOSM_COMMIT);
01405         iosm->path = _free(iosm->path);
01406         iosm->li->filex[i] = -1;
01407     }
01408 
01409     iosm->ix = iterIndex;
01410     iosm->nsuffix = nsuffix;
01411     iosm->path = path;
01412     return rc;
01413 }
01414 /*@=compdef@*/
01415 
01421 static int iosmRmdirs(/*@special@*/ /*@partial@*/ IOSM_t iosm)
01422         /*@uses iosm->path, iosm->dnlx, iosm->ldn, iosm->rdbuf, iosm->iter @*/
01423         /*@globals h_errno, fileSystem, internalState @*/
01424         /*@modifies iosm, fileSystem, internalState @*/
01425 {
01426     const char * path = iosm->path;
01427     void * dnli = dnlInitIterator(iosm, 1);
01428     char * dn = iosm->rdbuf;
01429     int dc = dnlCount(dnli);
01430     int rc = 0;
01431 
01432     iosm->path = NULL;
01433     dn[0] = '\0';
01434     /*@-observertrans -dependenttrans@*/
01435     if (iosm->ldn != NULL && iosm->dnlx != NULL)
01436     while ((iosm->path = dnlNextIterator(dnli)) != NULL) {
01437         size_t dnlen = strlen(iosm->path);
01438         char * te;
01439 
01440         dc = dnlIndex(dnli);
01441         if (iosm->dnlx[dc] < 1 || (size_t)iosm->dnlx[dc] >= dnlen)
01442             continue;
01443 
01444         /* Copy to avoid const on iosm->path. */
01445         te = stpcpy(dn, iosm->path) - 1;
01446         iosm->path = dn;
01447 
01448         /* Remove generated directories. */
01449         /*@-usereleased@*/ /* LCL: te used after release? */
01450         do {
01451             if (*te == '/') {
01452                 *te = '\0';
01453 /*@-compdef@*/
01454                 rc = iosmNext(iosm, IOSM_RMDIR);
01455 /*@=compdef@*/
01456                 *te = '/';
01457             }
01458             if (rc)
01459                 /*@innerbreak@*/ break;
01460             te--;
01461         } while ((te - iosm->path) > iosm->dnlx[dc]);
01462         /*@=usereleased@*/
01463     }
01464     dnli = dnlFreeIterator(dnli);
01465     /*@=observertrans =dependenttrans@*/
01466 
01467     iosm->path = path;
01468     return rc;
01469 }
01470 
01476 static int iosmMkdirs(/*@special@*/ /*@partial@*/ IOSM_t iosm)
01477         /*@uses iosm->path, iosm->sb, iosm->osb, iosm->rdbuf, iosm->iter,
01478                 iosm->ldn, iosm->ldnlen, iosm->ldnalloc @*/
01479         /*@defines iosm->dnlx, iosm->ldn @*/
01480         /*@globals h_errno, fileSystem, internalState @*/
01481         /*@modifies iosm, fileSystem, internalState @*/
01482 {
01483     struct stat * st = &iosm->sb;
01484     struct stat * ost = &iosm->osb;
01485     const char * path = iosm->path;
01486     mode_t st_mode = st->st_mode;
01487     void * dnli = dnlInitIterator(iosm, 0);
01488     char * dn = iosm->rdbuf;
01489     int dc = dnlCount(dnli);
01490     int rc = 0;
01491     size_t i;
01492 
01493     iosm->path = NULL;
01494 
01495     dn[0] = '\0';
01496     iosm->dnlx = (dc ? xcalloc(dc, sizeof(*iosm->dnlx)) : NULL);
01497     /*@-observertrans -dependenttrans@*/
01498     if (iosm->dnlx != NULL)
01499     while ((iosm->path = dnlNextIterator(dnli)) != NULL) {
01500         size_t dnlen = strlen(iosm->path);
01501         char * te;
01502 
01503         dc = dnlIndex(dnli);
01504         if (dc < 0) continue;
01505         iosm->dnlx[dc] = (unsigned short) dnlen;
01506         if (dnlen <= 1)
01507             continue;
01508 
01509         /*@-compdef -nullpass@*/        /* FIX: iosm->ldn not defined ??? */
01510         if (dnlen <= iosm->ldnlen && !strcmp(iosm->path, iosm->ldn))
01511             continue;
01512         /*@=compdef =nullpass@*/
01513 
01514         /* Copy to avoid const on iosm->path. */
01515         (void) stpcpy(dn, iosm->path);
01516         iosm->path = dn;
01517 
01518         /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
01519         (void) urlPath(dn, (const char **)&te);
01520         for (i = 1, te++; *te != '\0'; te++, i++) {
01521             if (*te != '/')
01522                 /*@innercontinue@*/ continue;
01523 
01524             *te = '\0';
01525 
01526             /* Already validated? */
01527             /*@-usedef -compdef -nullpass -nullderef@*/
01528             if (i < iosm->ldnlen &&
01529                 (iosm->ldn[i] == '/' || iosm->ldn[i] == '\0') &&
01530                 !strncmp(iosm->path, iosm->ldn, i))
01531             {
01532                 *te = '/';
01533                 /* Move pre-existing path marker forward. */
01534                 iosm->dnlx[dc] = (te - dn);
01535                 /*@innercontinue@*/ continue;
01536             }
01537             /*@=usedef =compdef =nullpass =nullderef@*/
01538 
01539             /* Validate next component of path. */
01540             rc = iosmUNSAFE(iosm, IOSM_LSTAT);
01541             *te = '/';
01542 
01543             /* Directory already exists? */
01544             if (rc == 0 && S_ISDIR(ost->st_mode)) {
01545                 /* Move pre-existing path marker forward. */
01546                 iosm->dnlx[dc] = (te - dn);
01547             } else if (rc == IOSMERR_ENOENT) {
01548                 rpmfi fi = iosmGetFi(iosm);
01549                 *te = '\0';
01550                 st->st_mode = S_IFDIR | (fi->dperms & 07777);
01551                 rc = iosmNext(iosm, IOSM_MKDIR);
01552                 if (!rc) {
01553 #if defined(_USE_RPMSX)
01554                     security_context_t scon = NULL;
01555                     /* XXX FIXME? only new dir will have context set. */
01556                     /* Get file security context from patterns. */
01557                     if (!fsm->nofcontexts
01558                      && !matchpathcon(iosm->path, st->st_mode, &scon)
01559                      && scon != NULL)
01560                     {
01561                         iosm->fcontext = scon;
01562                         rc = iosmNext(iosm, IOSM_LSETFCON);
01563                     } else
01564 #endif
01565                         iosm->fcontext = NULL;
01566                     if (iosm->fcontext == NULL)
01567                         rpmlog(RPMLOG_DEBUG,
01568                             D_("%s directory created with perms %04o, no context.\n"),
01569                             iosm->path, (unsigned)(st->st_mode & 07777));
01570                     else {
01571                         rpmlog(RPMLOG_DEBUG,
01572                             D_("%s directory created with perms %04o, context %s.\n"),
01573                             iosm->path, (unsigned)(st->st_mode & 07777),
01574                             iosm->fcontext);
01575 #if defined(_USE_RPMSX)
01576                         iosm->fcontext = NULL;
01577                         scon = _free(scon);
01578 #endif
01579                     }
01580                 }
01581                 *te = '/';
01582             }
01583             if (rc)
01584                 /*@innerbreak@*/ break;
01585         }
01586         if (rc) break;
01587 
01588         /* Save last validated path. */
01589 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01590         if (iosm->ldnalloc < (dnlen + 1)) {
01591             iosm->ldnalloc = dnlen + 100;
01592             iosm->ldn = xrealloc(iosm->ldn, iosm->ldnalloc);
01593         }
01594         if (iosm->ldn != NULL) {        /* XXX can't happen */
01595             strcpy(iosm->ldn, iosm->path);
01596             iosm->ldnlen = dnlen;
01597         }
01598 /*@=compdef@*/
01599     }
01600     dnli = dnlFreeIterator(dnli);
01601     /*@=observertrans =dependenttrans@*/
01602 
01603     iosm->path = path;
01604     st->st_mode = st_mode;              /* XXX restore st->st_mode */
01605 /*@-compdef@*/ /* FIX: ldn/path annotations ? */
01606     return rc;
01607 /*@=compdef@*/
01608 }
01609 
01610 #ifdef  NOTYET
01611 
01616 static int iosmStat(/*@special@*/ /*@partial@*/ IOSM_t iosm)
01617         /*@globals fileSystem, internalState @*/
01618         /*@modifies iosm, fileSystem, internalState @*/
01619 {
01620     int rc = 0;
01621 
01622     if (iosm->path != NULL) {
01623         int saveernno = errno;
01624         rc = iosmUNSAFE(iosm, (!(iosm->mapFlags & IOSM_FOLLOW_SYMLINKS)
01625                         ? IOSM_LSTAT : IOSM_STAT));
01626         if (rc == IOSMERR_ENOENT) {
01627             errno = saveerrno;
01628             rc = 0;
01629             iosm->exists = 0;
01630         } else if (rc == 0) {
01631             iosm->exists = 1;
01632         }
01633     } else {
01634         /* Skip %ghost files on build. */
01635         iosm->exists = 0;
01636     }
01637     return rc;
01638 }
01639 #endif
01640 
01641 #define IS_DEV_LOG(_x)  \
01642         ((_x) != NULL && strlen(_x) >= (sizeof("/dev/log")-1) && \
01643         !strncmp((_x), "/dev/log", sizeof("/dev/log")-1) && \
01644         ((_x)[sizeof("/dev/log")-1] == '\0' || \
01645          (_x)[sizeof("/dev/log")-1] == ';'))
01646 
01647 /*@-compmempass@*/
01648 int iosmStage(IOSM_t iosm, iosmFileStage stage)
01649 {
01650 #ifdef  NOTUSED
01651     iosmFileStage prevStage = iosm->stage;
01652     const char * const prev = iosmFileStageString(prevStage);
01653 #endif
01654     const char * const cur = iosmFileStageString(stage);
01655     struct stat * st = &iosm->sb;
01656     struct stat * ost = &iosm->osb;
01657     int saveerrno = errno;
01658     int rc = iosm->rc;
01659     size_t left;
01660     int i;
01661 
01662 #define _fafilter(_a)   \
01663     (!((_a) == FA_CREATE || (_a) == FA_ERASE || (_a) == FA_COPYIN || (_a) == FA_COPYOUT) \
01664         ? iosmFileActionString(_a) : "")
01665 
01666     if (stage & IOSM_DEAD) {
01667         /* do nothing */
01668     } else if (stage & IOSM_INTERNAL) {
01669         if (iosm->debug && !(stage & IOSM_SYSCALL))
01670             rpmlog(RPMLOG_DEBUG, " %8s %06o%3d (%4d,%4d)%12lu %s %s\n",
01671                 cur,
01672                 (unsigned)st->st_mode, (int)st->st_nlink,
01673                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01674                 (iosm->path ? iosm->path : ""),
01675                 _fafilter(iosm->action));
01676     } else {
01677         const char * apath = NULL;
01678         if (iosm->path)
01679             (void) urlPath(iosm->path, &apath);
01680         iosm->stage = stage;
01681         if (iosm->debug || !(stage & IOSM_VERBOSE))
01682             rpmlog(RPMLOG_DEBUG, "%-8s  %06o%3d (%4d,%4d)%12lu %s %s\n",
01683                 cur,
01684                 (unsigned)st->st_mode, (int)st->st_nlink,
01685                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
01686                 (apath ? apath + iosm->astriplen : ""),
01687                 _fafilter(iosm->action));
01688     }
01689 #undef  _fafilter
01690 
01691     switch (stage) {
01692     case IOSM_UNKNOWN:
01693         break;
01694     case IOSM_PKGINSTALL:
01695         while (1) {
01696             /* Clean iosm, free'ing memory. Read next archive header. */
01697             rc = iosmUNSAFE(iosm, IOSM_INIT);
01698 
01699             /* Exit on end-of-payload. */
01700             if (rc == IOSMERR_HDR_TRAILER) {
01701                 rc = 0;
01702                 /*@loopbreak@*/ break;
01703             }
01704 
01705             /* Exit on error. */
01706             if (rc) {
01707                 iosm->postpone = 1;
01708                 (void) iosmNext(iosm, IOSM_UNDO);
01709                 /*@loopbreak@*/ break;
01710             }
01711 
01712             /* Extract file from archive. */
01713             rc = iosmNext(iosm, IOSM_PROCESS);
01714             if (rc) {
01715                 (void) iosmNext(iosm, IOSM_UNDO);
01716                 /*@loopbreak@*/ break;
01717             }
01718 
01719             /* Notify on success. */
01720             (void) iosmNext(iosm, IOSM_NOTIFY);
01721 
01722             rc = iosmNext(iosm, IOSM_FINI);
01723             if (rc) {
01724                 /*@loopbreak@*/ break;
01725             }
01726         }
01727         break;
01728     case IOSM_PKGERASE:
01729     case IOSM_PKGCOMMIT:
01730         while (1) {
01731             /* Clean iosm, free'ing memory. */
01732             rc = iosmUNSAFE(iosm, IOSM_INIT);
01733 
01734             /* Exit on end-of-payload. */
01735             if (rc == IOSMERR_HDR_TRAILER) {
01736                 rc = 0;
01737                 /*@loopbreak@*/ break;
01738             }
01739 
01740             /* Rename/erase next item. */
01741             if (iosmNext(iosm, IOSM_FINI))
01742                 /*@loopbreak@*/ break;
01743         }
01744         break;
01745     case IOSM_PKGBUILD:
01746         while (1) {
01747 
01748             rc = iosmUNSAFE(iosm, IOSM_INIT);
01749 
01750             /* Exit on end-of-payload. */
01751             if (rc == IOSMERR_HDR_TRAILER) {
01752                 rc = 0;
01753                 /*@loopbreak@*/ break;
01754             }
01755 
01756             /* Exit on error. */
01757             if (rc) {
01758                 iosm->postpone = 1;
01759                 (void) iosmNext(iosm, IOSM_UNDO);
01760                 /*@loopbreak@*/ break;
01761             }
01762 
01763             /* Copy file into archive. */
01764             rc = iosmNext(iosm, IOSM_PROCESS);
01765             if (rc) {
01766                 (void) iosmNext(iosm, IOSM_UNDO);
01767                 /*@loopbreak@*/ break;
01768             }
01769 
01770             /* Notify on success. */
01771             (void) iosmNext(iosm, IOSM_NOTIFY);
01772 
01773             if (iosmNext(iosm, IOSM_FINI))
01774                 /*@loopbreak@*/ break;
01775         }
01776 
01777         /* Flush partial sets of hard linked files. */
01778         if (!(iosm->mapFlags & IOSM_ALL_HARDLINKS)) {
01779             int nlink, j;
01780             while ((iosm->li = iosm->links) != NULL) {
01781                 iosm->links = iosm->li->next;
01782                 iosm->li->next = NULL;
01783 
01784                 /* Re-calculate link count for archive header. */
01785                 for (j = -1, nlink = 0, i = 0; i < iosm->li->nlink; i++) {
01786                     if (iosm->li->filex[i] < 0)
01787                         /*@innercontinue@*/ continue;
01788                     nlink++;
01789                     if (j == -1) j = i;
01790                 }
01791                 /* XXX force the contents out as well. */
01792                 if (j != 0) {
01793                     iosm->li->filex[0] = iosm->li->filex[j];
01794                     iosm->li->filex[j] = -1;
01795                 }
01796                 iosm->li->sb.st_nlink = nlink;
01797 
01798                 iosm->sb = iosm->li->sb;        /* structure assignment */
01799                 iosm->osb = iosm->sb;   /* structure assignment */
01800 
01801                 if (!rc) rc = writeLinkedFile(iosm);
01802 
01803                 iosm->li = freeHardLink(iosm->li);
01804             }
01805         }
01806 
01807         if (!rc)
01808             rc = iosmNext(iosm, IOSM_TRAILER);
01809 
01810         break;
01811     case IOSM_CREATE:
01812         iosm->path = _free(iosm->path);
01813         iosm->lpath = _free(iosm->lpath);
01814         iosm->opath = _free(iosm->opath);
01815         iosm->dnlx = _free(iosm->dnlx);
01816 
01817         iosm->ldn = _free(iosm->ldn);
01818         iosm->ldnalloc = iosm->ldnlen = 0;
01819 
01820         iosm->rdsize = iosm->wrsize = 0;
01821         iosm->rdbuf = iosm->rdb = _free(iosm->rdb);
01822         iosm->wrbuf = iosm->wrb = _free(iosm->wrb);
01823         if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
01824             iosm->rdsize = 16 * BUFSIZ;
01825             iosm->rdbuf = iosm->rdb = xmalloc(iosm->rdsize);
01826             iosm->wrsize = 16 * BUFSIZ;
01827             iosm->wrbuf = iosm->wrb = xmalloc(iosm->wrsize);
01828         }
01829 
01830         iosm->mkdirsdone = 0;
01831         iosm->ix = -1;
01832         iosm->links = NULL;
01833         iosm->li = NULL;
01834         errno = 0;      /* XXX get rid of EBADF */
01835 
01836         /* Detect and create directories not explicitly in package. */
01837         if (iosm->goal == IOSM_PKGINSTALL) {
01838 /*@-compdef@*/
01839             rc = iosmNext(iosm, IOSM_MKDIRS);
01840 /*@=compdef@*/
01841             if (!rc) iosm->mkdirsdone = 1;
01842         }
01843 
01844         break;
01845     case IOSM_INIT:
01846         iosm->path = _free(iosm->path);
01847         iosm->lpath = _free(iosm->lpath);
01848         iosm->postpone = 0;
01849         iosm->diskchecked = iosm->exists = 0;
01850         iosm->subdir = NULL;
01851         iosm->suffix = (iosm->sufbuf[0] != '\0' ? iosm->sufbuf : NULL);
01852         iosm->action = FA_UNKNOWN;
01853         iosm->osuffix = NULL;
01854         iosm->nsuffix = NULL;
01855 
01856         if (iosm->goal == IOSM_PKGINSTALL) {
01857             /* Read next header from payload, checking for end-of-payload. */
01858             rc = iosmUNSAFE(iosm, IOSM_NEXT);
01859         }
01860         if (rc) break;
01861 
01862         /* Identify mapping index. */
01863         iosm->ix = ((iosm->goal == IOSM_PKGINSTALL)
01864                 ? mapFind(iosm->iter, iosm->path) : mapNextIterator(iosm->iter));
01865 
01866 { rpmfi fi = iosmGetFi(iosm);
01867 if (!(fi->mapflags & IOSM_PAYLOAD_LIST)) {
01868         /* Detect end-of-loop and/or mapping error. */
01869 if (!(fi->mapflags & IOSM_PAYLOAD_EXTRACT)) {
01870         if (iosm->ix < 0) {
01871             if (iosm->goal == IOSM_PKGINSTALL) {
01872 #if 0
01873                 rpmlog(RPMLOG_WARNING,
01874                     _("archive file %s was not found in header file list\n"),
01875                         iosm->path);
01876 #endif
01877                 if (iosm->failedFile && *iosm->failedFile == NULL)
01878                     *iosm->failedFile = xstrdup(iosm->path);
01879                 rc = IOSMERR_UNMAPPED_FILE;
01880             } else {
01881                 rc = IOSMERR_HDR_TRAILER;
01882             }
01883             break;
01884         }
01885 }
01886 
01887         /* On non-install, mode must be known so that dirs don't get suffix. */
01888         if (iosm->goal != IOSM_PKGINSTALL) {
01889             st->st_mode = fi->fmodes[iosm->ix];
01890         }
01891 }
01892 }
01893 
01894         /* Generate file path. */
01895         rc = iosmNext(iosm, IOSM_MAP);
01896         if (rc) break;
01897 
01898         /* Perform lstat/stat for disk file. */
01899 #ifdef  NOTYET
01900         rc = iosmStat(iosm);
01901 #else
01902         if (iosm->path != NULL &&
01903             !(iosm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode)))
01904         {
01905             rc = iosmUNSAFE(iosm, (!(iosm->mapFlags & IOSM_FOLLOW_SYMLINKS)
01906                         ? IOSM_LSTAT : IOSM_STAT));
01907             if (rc == IOSMERR_ENOENT) {
01908                 errno = saveerrno;
01909                 rc = 0;
01910                 iosm->exists = 0;
01911             } else if (rc == 0) {
01912                 iosm->exists = 1;
01913             }
01914         } else {
01915             /* Skip %ghost files on build. */
01916             iosm->exists = 0;
01917         }
01918 #endif
01919         iosm->diskchecked = 1;
01920         if (rc) break;
01921 
01922         /* On non-install, the disk file stat is what's remapped. */
01923         if (iosm->goal != IOSM_PKGINSTALL)
01924             *st = *ost;                 /* structure assignment */
01925 
01926         /* Remap file perms, owner, and group. */
01927         rc = iosmMapAttrs(iosm);
01928         if (rc) break;
01929 
01930         iosm->postpone = iosmFileActionSkipped(iosm->action);
01931         if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
01932             /*@-evalorder@*/ /* FIX: saveHardLink can modify iosm */
01933             if (S_ISREG(st->st_mode) && st->st_nlink > 1)
01934                 iosm->postpone = saveHardLink(iosm);
01935             /*@=evalorder@*/
01936         }
01937 { rpmfi fi = iosmGetFi(iosm);
01938 if (fi->mapflags & IOSM_PAYLOAD_LIST) iosm->postpone = 1;
01939 }
01940         break;
01941     case IOSM_PRE:
01942         break;
01943     case IOSM_MAP:
01944         rc = iosmMapPath(iosm);
01945         break;
01946     case IOSM_MKDIRS:
01947         rc = iosmMkdirs(iosm);
01948         break;
01949     case IOSM_RMDIRS:
01950         if (iosm->dnlx)
01951             rc = iosmRmdirs(iosm);
01952         break;
01953     case IOSM_PROCESS:
01954         if (iosm->postpone) {
01955             if (iosm->goal == IOSM_PKGINSTALL) {
01956                 /* XXX Skip over file body, archive headers already done. */
01957                 if (S_ISREG(st->st_mode))
01958                     rc = iosmNext(iosm, IOSM_EAT);
01959             }
01960             break;
01961         }
01962 
01963         if (iosm->goal == IOSM_PKGBUILD) {
01964             if (iosm->fflags & RPMFILE_GHOST) /* XXX Don't if %ghost file. */
01965                 break;
01966             if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
01967                 struct hardLink_s * li, * prev;
01968 
01969 if (!(iosm->mapFlags & IOSM_ALL_HARDLINKS)) break;
01970                 rc = writeLinkedFile(iosm);
01971                 if (rc) break;  /* W2DO? */
01972 
01973                 for (li = iosm->links, prev = NULL; li; prev = li, li = li->next)
01974                      if (li == iosm->li)
01975                         /*@loopbreak@*/ break;
01976 
01977                 if (prev == NULL)
01978                     iosm->links = iosm->li->next;
01979                 else
01980                     prev->next = iosm->li->next;
01981                 iosm->li->next = NULL;
01982                 iosm->li = freeHardLink(iosm->li);
01983             } else {
01984                 rc = writeFile(iosm, 1);
01985             }
01986             break;
01987         }
01988 
01989         if (iosm->goal != IOSM_PKGINSTALL)
01990             break;
01991 
01992         if (S_ISREG(st->st_mode) && iosm->lpath != NULL) {
01993             const char * opath = iosm->opath;
01994             char * t = xmalloc(strlen(iosm->lpath+1) + strlen(iosm->suffix) + 1);
01995             (void) stpcpy(t, iosm->lpath+1);
01996              iosm->opath = t;
01997             /* XXX link(iosm->opath, iosm->path) */
01998             rc = iosmNext(iosm, IOSM_LINK);
01999             if (iosm->failedFile && rc != 0 && *iosm->failedFile == NULL) {
02000                 *iosm->failedFile = xstrdup(iosm->path);
02001             }
02002             iosm->opath = _free(iosm->opath);
02003             iosm->opath = opath;
02004             break;      /* XXX so that delayed hard links get skipped. */
02005         }
02006         if (S_ISREG(st->st_mode)) {
02007             const char * path = iosm->path;
02008             if (iosm->osuffix)
02009                 iosm->path = iosmFsPath(iosm, st, NULL, NULL);
02010             rc = iosmUNSAFE(iosm, IOSM_VERIFY);
02011 
02012             if (rc == 0 && iosm->osuffix) {
02013                 const char * opath = iosm->opath;
02014                 iosm->opath = iosm->path;
02015                 iosm->path = iosmFsPath(iosm, st, NULL, iosm->osuffix);
02016                 rc = iosmNext(iosm, IOSM_RENAME);
02017                 if (!rc)
02018                     rpmlog(RPMLOG_WARNING,
02019                         _("%s saved as %s\n"),
02020                                 (iosm->opath ? iosm->opath : ""),
02021                                 (iosm->path ? iosm->path : ""));
02022                 iosm->path = _free(iosm->path);
02023                 iosm->opath = opath;
02024             }
02025 
02026             /*@-dependenttrans@*/
02027             iosm->path = path;
02028             /*@=dependenttrans@*/
02029             if (!(rc == IOSMERR_ENOENT)) return rc;
02030             rc = extractRegular(iosm);
02031         } else if (S_ISDIR(st->st_mode)) {
02032             mode_t st_mode = st->st_mode;
02033             rc = iosmUNSAFE(iosm, IOSM_VERIFY);
02034             if (rc == IOSMERR_ENOENT) {
02035                 st->st_mode &= ~07777;          /* XXX abuse st->st_mode */
02036                 st->st_mode |=  00700;
02037                 rc = iosmNext(iosm, IOSM_MKDIR);
02038                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
02039             }
02040         } else if (S_ISLNK(st->st_mode)) {
02041 assert(iosm->lpath != NULL);
02042             rc = iosmUNSAFE(iosm, IOSM_VERIFY);
02043             if (rc == IOSMERR_ENOENT)
02044                 rc = iosmNext(iosm, IOSM_SYMLINK);
02045         } else if (S_ISFIFO(st->st_mode)) {
02046             mode_t st_mode = st->st_mode;
02047             /* This mimics cpio S_ISSOCK() behavior but probably isnt' right */
02048             rc = iosmUNSAFE(iosm, IOSM_VERIFY);
02049             if (rc == IOSMERR_ENOENT) {
02050                 st->st_mode = 0000;             /* XXX abuse st->st_mode */
02051                 rc = iosmNext(iosm, IOSM_MKFIFO);
02052                 st->st_mode = st_mode;          /* XXX restore st->st_mode */
02053             }
02054         } else if (S_ISCHR(st->st_mode) ||
02055                    S_ISBLK(st->st_mode) ||
02056     /*@-unrecog@*/ S_ISSOCK(st->st_mode) /*@=unrecog@*/)
02057         {
02058             rc = iosmUNSAFE(iosm, IOSM_VERIFY);
02059             if (rc == IOSMERR_ENOENT)
02060                 rc = iosmNext(iosm, IOSM_MKNOD);
02061         } else {
02062             /* XXX Repackaged payloads may be missing files. */
02063             if (iosm->repackaged)
02064                 break;
02065 
02066             /* XXX Special case /dev/log, which shouldn't be packaged anyways */
02067             if (!IS_DEV_LOG(iosm->path))
02068                 rc = IOSMERR_UNKNOWN_FILETYPE;
02069         }
02070         if (S_ISREG(st->st_mode) && st->st_nlink > 1) {
02071             iosm->li->createdPath = iosm->li->linkIndex;
02072             rc = iosmMakeLinks(iosm);
02073         }
02074         break;
02075     case IOSM_POST:
02076         break;
02077     case IOSM_MKLINKS:
02078         rc = iosmMakeLinks(iosm);
02079         break;
02080     case IOSM_NOTIFY:           /* XXX move from iosm to psm -> tsm */
02081         if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
02082             rpmfi fi = iosmGetFi(iosm);
02083             rpmuint64_t archivePos = fdGetCpioPos(iosm->cfd);
02084             if (archivePos > fi->archivePos) {
02085                 fi->archivePos = (unsigned long long) archivePos;
02086 #if defined(_USE_RPMTS)
02087                 (void) rpmtsNotify(iosmGetTs(iosm), fi->te,RPMCALLBACK_INST_PROGRESS,
02088                         fi->archivePos, fi->archiveSize);
02089 #endif
02090             }
02091         }
02092         break;
02093     case IOSM_UNDO:
02094         if (iosm->postpone)
02095             break;
02096         if (iosm->goal == IOSM_PKGINSTALL) {
02097             /* XXX only erase if temp fn w suffix is in use */
02098             if (iosm->sufbuf[0] != '\0')
02099                 (void) iosmNext(iosm,
02100                     (S_ISDIR(st->st_mode) ? IOSM_RMDIR : IOSM_UNLINK));
02101 
02102 #ifdef  NOTYET  /* XXX remove only dirs just created, not all. */
02103             if (iosm->dnlx)
02104                 (void) iosmNext(iosm, IOSM_RMDIRS);
02105 #endif
02106             errno = saveerrno;
02107         }
02108         if (iosm->failedFile && *iosm->failedFile == NULL)
02109             *iosm->failedFile = xstrdup(iosm->path);
02110         break;
02111     case IOSM_FINI:
02112         if (!iosm->postpone && iosm->commit) {
02113             if (iosm->goal == IOSM_PKGINSTALL)
02114                 rc = ((S_ISREG(st->st_mode) && st->st_nlink > 1)
02115                         ? iosmCommitLinks(iosm) : iosmNext(iosm, IOSM_COMMIT));
02116             if (iosm->goal == IOSM_PKGCOMMIT)
02117                 rc = iosmNext(iosm, IOSM_COMMIT);
02118             if (iosm->goal == IOSM_PKGERASE)
02119                 rc = iosmNext(iosm, IOSM_COMMIT);
02120         }
02121         iosm->path = _free(iosm->path);
02122         iosm->lpath = _free(iosm->lpath);
02123         iosm->opath = _free(iosm->opath);
02124         memset(st, 0, sizeof(*st));
02125         memset(ost, 0, sizeof(*ost));
02126         break;
02127     case IOSM_COMMIT:
02128         /* Rename pre-existing modified or unmanaged file. */
02129         if (iosm->osuffix && iosm->diskchecked &&
02130           (iosm->exists || (iosm->goal == IOSM_PKGINSTALL && S_ISREG(st->st_mode))))
02131         {
02132             const char * opath = iosm->opath;
02133             const char * path = iosm->path;
02134             iosm->opath = iosmFsPath(iosm, st, NULL, NULL);
02135             iosm->path = iosmFsPath(iosm, st, NULL, iosm->osuffix);
02136             rc = iosmNext(iosm, IOSM_RENAME);
02137             if (!rc) {
02138                 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"),
02139                                 (iosm->opath ? iosm->opath : ""),
02140                                 (iosm->path ? iosm->path : ""));
02141             }
02142             iosm->path = _free(iosm->path);
02143             iosm->path = path;
02144             iosm->opath = _free(iosm->opath);
02145             iosm->opath = opath;
02146         }
02147 
02148         /* Remove erased files. */
02149         if (iosm->goal == IOSM_PKGERASE) {
02150             if (iosm->action == FA_ERASE) {
02151                 if (S_ISDIR(st->st_mode)) {
02152                     rc = iosmNext(iosm, IOSM_RMDIR);
02153                     if (!rc) break;
02154                     switch (rc) {
02155                     case IOSMERR_ENOENT: /* XXX rmdir("/") linux 2.2.x kernel hack */
02156                     case IOSMERR_ENOTEMPTY:
02157         /* XXX make sure that build side permits %missingok on directories. */
02158                         if (iosm->fflags & RPMFILE_MISSINGOK)
02159                             /*@innerbreak@*/ break;
02160 
02161                         /* XXX common error message. */
02162                         rpmlog(
02163                             (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
02164                             _("rmdir of %s failed: Directory not empty\n"), 
02165                                 iosm->path);
02166                         /*@innerbreak@*/ break;
02167                     default:
02168                         rpmlog(
02169                             (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
02170                                 _("rmdir of %s failed: %s\n"),
02171                                 iosm->path, strerror(errno));
02172                         /*@innerbreak@*/ break;
02173                     }
02174                 } else {
02175                     rc = iosmNext(iosm, IOSM_UNLINK);
02176                     if (!rc) break;
02177                     switch (rc) {
02178                     case IOSMERR_ENOENT:
02179                         if (iosm->fflags & RPMFILE_MISSINGOK)
02180                             /*@innerbreak@*/ break;
02181                         /*@fallthrough@*/
02182                     default:
02183                         rpmlog(
02184                             (iosm->strict_erasures ? RPMLOG_ERR : RPMLOG_DEBUG),
02185                                 _("unlink of %s failed: %s\n"),
02186                                 iosm->path, strerror(errno));
02187                         /*@innerbreak@*/ break;
02188                     }
02189                 }
02190             }
02191             /* XXX Failure to remove is not (yet) cause for failure. */
02192             if (!iosm->strict_erasures) rc = 0;
02193             break;
02194         }
02195 
02196         /* XXX Special case /dev/log, which shouldn't be packaged anyways */
02197 { rpmfi fi = iosmGetFi(iosm);
02198 if (!(fi->mapflags & IOSM_PAYLOAD_EXTRACT)) {
02199         if (!S_ISSOCK(st->st_mode) && !IS_DEV_LOG(iosm->path)) {
02200             /* Rename temporary to final file name. */
02201             if (!S_ISDIR(st->st_mode) &&
02202                 (iosm->subdir || iosm->suffix || iosm->nsuffix))
02203             {
02204                 iosm->opath = iosm->path;
02205                 iosm->path = iosmFsPath(iosm, st, NULL, iosm->nsuffix);
02206                 rc = iosmNext(iosm, IOSM_RENAME);
02207                 if (rc)
02208                         (void) Unlink(iosm->opath);
02209                 else if (iosm->nsuffix) {
02210                     const char * opath = iosmFsPath(iosm, st, NULL, NULL);
02211                     rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
02212                                 (opath ? opath : ""),
02213                                 (iosm->path ? iosm->path : ""));
02214                     opath = _free(opath);
02215                 }
02216                 iosm->opath = _free(iosm->opath);
02217             }
02218             /*
02219              * Set file security context (if not disabled).
02220              */
02221             if (!rc && !getuid()) {
02222                 rc = iosmMapFContext(iosm);
02223                 if (!rc)
02224                     rc = iosmNext(iosm, IOSM_LSETFCON);
02225                 iosm->fcontext = NULL;
02226             }
02227             if (S_ISLNK(st->st_mode)) {
02228                 if (!rc && !getuid())
02229                     rc = iosmNext(iosm, IOSM_LCHOWN);
02230             } else {
02231                 if (!rc && !getuid())
02232                     rc = iosmNext(iosm, IOSM_CHOWN);
02233                 if (!rc)
02234                     rc = iosmNext(iosm, IOSM_CHMOD);
02235                 if (!rc) {
02236                     time_t mtime = st->st_mtime;
02237                     if (fi->fmtimes)
02238                         st->st_mtime = fi->fmtimes[iosm->ix];
02239                     rc = iosmNext(iosm, IOSM_UTIME);
02240                     st->st_mtime = mtime;
02241                 }
02242             }
02243         }
02244 }
02245 }
02246 
02247         /* Notify on success. */
02248         if (!rc)                rc = iosmNext(iosm, IOSM_NOTIFY);
02249         else if (iosm->failedFile && *iosm->failedFile == NULL) {
02250             *iosm->failedFile = iosm->path;
02251             iosm->path = NULL;
02252         }
02253         break;
02254     case IOSM_DESTROY:
02255         iosm->path = _free(iosm->path);
02256 
02257         /* Check for hard links missing from payload. */
02258         while ((iosm->li = iosm->links) != NULL) {
02259             iosm->links = iosm->li->next;
02260             iosm->li->next = NULL;
02261             if (iosm->goal == IOSM_PKGINSTALL &&
02262                         iosm->commit && iosm->li->linksLeft)
02263             {
02264                 for (i = 0 ; i < iosm->li->linksLeft; i++) {
02265                     if (iosm->li->filex[i] < 0)
02266                         /*@innercontinue@*/ continue;
02267                     rc = IOSMERR_MISSING_HARDLINK;
02268                     if (iosm->failedFile && *iosm->failedFile == NULL) {
02269                         iosm->ix = iosm->li->filex[i];
02270                         if (!iosmNext(iosm, IOSM_MAP)) {
02271                             *iosm->failedFile = iosm->path;
02272                             iosm->path = NULL;
02273                         }
02274                     }
02275                     /*@loopbreak@*/ break;
02276                 }
02277             }
02278             if (iosm->goal == IOSM_PKGBUILD &&
02279                 (iosm->mapFlags & IOSM_ALL_HARDLINKS))
02280             {
02281                 rc = IOSMERR_MISSING_HARDLINK;
02282             }
02283             iosm->li = freeHardLink(iosm->li);
02284         }
02285         iosm->ldn = _free(iosm->ldn);
02286         iosm->ldnalloc = iosm->ldnlen = 0;
02287         iosm->rdbuf = iosm->rdb = _free(iosm->rdb);
02288         iosm->wrbuf = iosm->wrb = _free(iosm->wrb);
02289         break;
02290     case IOSM_VERIFY:
02291         if (iosm->diskchecked && !iosm->exists) {
02292             rc = IOSMERR_ENOENT;
02293             break;
02294         }
02295         if (S_ISREG(st->st_mode)) {
02296             char * path = alloca(strlen(iosm->path) + sizeof("-RPMDELETE"));
02297             (void) stpcpy( stpcpy(path, iosm->path), "-RPMDELETE");
02298             /*
02299              * XXX HP-UX (and other os'es) don't permit unlink on busy
02300              * XXX files.
02301              */
02302             iosm->opath = iosm->path;
02303             iosm->path = path;
02304             rc = iosmNext(iosm, IOSM_RENAME);
02305             if (!rc)
02306                     (void) iosmNext(iosm, IOSM_UNLINK);
02307             else
02308                     rc = IOSMERR_UNLINK_FAILED;
02309             iosm->path = iosm->opath;
02310             iosm->opath = NULL;
02311             return (rc ? rc : IOSMERR_ENOENT);  /* XXX HACK */
02312             /*@notreached@*/ break;
02313         } else if (S_ISDIR(st->st_mode)) {
02314             if (S_ISDIR(ost->st_mode))          return 0;
02315             if (S_ISLNK(ost->st_mode)) {
02316                 rc = iosmUNSAFE(iosm, IOSM_STAT);
02317                 if (rc == IOSMERR_ENOENT) rc = 0;
02318                 if (rc) break;
02319                 errno = saveerrno;
02320                 if (S_ISDIR(ost->st_mode))      return 0;
02321             }
02322         } else if (S_ISLNK(st->st_mode)) {
02323             if (S_ISLNK(ost->st_mode)) {
02324         /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */
02325                 rc = iosmUNSAFE(iosm, IOSM_READLINK);
02326                 errno = saveerrno;
02327                 if (rc) break;
02328                 if (!strcmp(iosm->lpath, iosm->rdbuf))  return 0;
02329             }
02330         } else if (S_ISFIFO(st->st_mode)) {
02331             if (S_ISFIFO(ost->st_mode))         return 0;
02332         } else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
02333             if ((S_ISCHR(ost->st_mode) || S_ISBLK(ost->st_mode)) &&
02334                 (ost->st_rdev == st->st_rdev))  return 0;
02335         } else if (S_ISSOCK(st->st_mode)) {
02336             if (S_ISSOCK(ost->st_mode))         return 0;
02337         }
02338             /* XXX shouldn't do this with commit/undo. */
02339         rc = 0;
02340         if (iosm->stage == IOSM_PROCESS) rc = iosmNext(iosm, IOSM_UNLINK);
02341         if (rc == 0)    rc = IOSMERR_ENOENT;
02342         return (rc ? rc : IOSMERR_ENOENT);      /* XXX HACK */
02343         /*@notreached@*/ break;
02344 
02345     case IOSM_UNLINK:
02346         /* XXX Remove setuid/setgid bits on possibly hard linked files. */
02347         if (iosm->mapFlags & IOSM_SBIT_CHECK) {
02348             struct stat stb;
02349             if (Lstat(iosm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
02350                 /* XXX rc = iosmNext(iosm, IOSM_CHMOD); instead */
02351                 (void)Chmod(iosm->path, stb.st_mode & 0777);
02352             }
02353         }
02354         rc = Unlink(iosm->path);
02355         if (iosm->debug && (stage & IOSM_SYSCALL))
02356             rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", cur,
02357                 iosm->path, (rc < 0 ? strerror(errno) : ""));
02358         if (rc < 0)
02359             rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_UNLINK_FAILED);
02360         break;
02361     case IOSM_RENAME:
02362         /* XXX Remove setuid/setgid bits on possibly hard linked files. */
02363         if (iosm->mapFlags & IOSM_SBIT_CHECK) {
02364             struct stat stb;
02365             if (Lstat(iosm->path, &stb) == 0 && S_ISREG(stb.st_mode) && (stb.st_mode & 06000) != 0) {
02366                 /* XXX rc = iosmNext(iosm, IOSM_CHMOD); instead */
02367                 (void)Chmod(iosm->path, stb.st_mode & 0777);
02368             }
02369         }
02370         rc = Rename(iosm->opath, iosm->path);
02371         /* XXX Repackaged payloads may be missing files. */
02372         if (iosm->repackaged)
02373             rc = 0;
02374 #if defined(ETXTBSY)
02375         if (rc && errno == ETXTBSY) {
02376             char * path = alloca(strlen(iosm->path) + sizeof("-RPMDELETE"));
02377             (void) stpcpy( stpcpy(path, iosm->path), "-RPMDELETE");
02378             /*
02379              * XXX HP-UX (and other os'es) don't permit rename to busy
02380              * XXX files.
02381              */
02382             rc = Rename(iosm->path, path);
02383             if (!rc) rc = Rename(iosm->opath, iosm->path);
02384         }
02385 #endif
02386         if (iosm->debug && (stage & IOSM_SYSCALL))
02387             rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
02388                 iosm->opath, iosm->path, (rc < 0 ? strerror(errno) : ""));
02389         if (rc < 0)     rc = IOSMERR_RENAME_FAILED;
02390         break;
02391     case IOSM_MKDIR:
02392         rc = Mkdir(iosm->path, (st->st_mode & 07777));
02393         if (iosm->debug && (stage & IOSM_SYSCALL))
02394             rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02395                 iosm->path, (unsigned)(st->st_mode & 07777),
02396                 (rc < 0 ? strerror(errno) : ""));
02397         if (rc < 0)     rc = IOSMERR_MKDIR_FAILED;
02398         break;
02399     case IOSM_RMDIR:
02400         rc = Rmdir(iosm->path);
02401         if (iosm->debug && (stage & IOSM_SYSCALL))
02402             rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", cur,
02403                 iosm->path, (rc < 0 ? strerror(errno) : ""));
02404         if (rc < 0)
02405             switch (errno) {
02406             case ENOENT:        rc = IOSMERR_ENOENT;    /*@switchbreak@*/ break;
02407             case ENOTEMPTY:     rc = IOSMERR_ENOTEMPTY; /*@switchbreak@*/ break;
02408             default:            rc = IOSMERR_RMDIR_FAILED; /*@switchbreak@*/ break;
02409             }
02410         break;
02411     case IOSM_LSETFCON:
02412       { const char * iosmpath = NULL;
02413         if (iosm->fcontext == NULL || *iosm->fcontext == '\0'
02414          || !strcmp(iosm->fcontext, "<<none>>"))
02415             break;
02416         (void) urlPath(iosm->path, &iosmpath);  /* XXX iosm->path */
02417         rc = lsetfilecon(iosmpath, (security_context_t)iosm->fcontext);
02418         if (iosm->debug && (stage & IOSM_SYSCALL))
02419             rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
02420                 iosm->path, iosm->fcontext,
02421                 (rc < 0 ? strerror(errno) : ""));
02422         if (rc < 0) rc = (errno == EOPNOTSUPP ? 0 : IOSMERR_LSETFCON_FAILED);
02423       } break;
02424     case IOSM_CHOWN:
02425         rc = Chown(iosm->path, st->st_uid, st->st_gid);
02426         if (iosm->debug && (stage & IOSM_SYSCALL))
02427             rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
02428                 iosm->path, (int)st->st_uid, (int)st->st_gid,
02429                 (rc < 0 ? strerror(errno) : ""));
02430         if (rc < 0)     rc = IOSMERR_CHOWN_FAILED;
02431         break;
02432     case IOSM_LCHOWN:
02433 #if ! CHOWN_FOLLOWS_SYMLINK
02434         rc = Lchown(iosm->path, st->st_uid, st->st_gid);
02435         if (iosm->debug && (stage & IOSM_SYSCALL))
02436             rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", cur,
02437                 iosm->path, (int)st->st_uid, (int)st->st_gid,
02438                 (rc < 0 ? strerror(errno) : ""));
02439         if (rc < 0)     rc = IOSMERR_CHOWN_FAILED;
02440 #endif
02441         break;
02442     case IOSM_CHMOD:
02443         rc = Chmod(iosm->path, (st->st_mode & 07777));
02444         if (iosm->debug && (stage & IOSM_SYSCALL))
02445             rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02446                 iosm->path, (unsigned)(st->st_mode & 07777),
02447                 (rc < 0 ? strerror(errno) : ""));
02448         if (rc < 0)     rc = IOSMERR_CHMOD_FAILED;
02449         break;
02450     case IOSM_UTIME:
02451         {   struct utimbuf stamp;
02452             stamp.actime = st->st_mtime;
02453             stamp.modtime = st->st_mtime;
02454             rc = Utime(iosm->path, &stamp);
02455             if (iosm->debug && (stage & IOSM_SYSCALL))
02456                 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", cur,
02457                         iosm->path, (unsigned)st->st_mtime,
02458                         (rc < 0 ? strerror(errno) : ""));
02459             if (rc < 0) rc = IOSMERR_UTIME_FAILED;
02460         }
02461         break;
02462     case IOSM_SYMLINK:
02463         rc = Symlink(iosm->lpath, iosm->path);
02464         if (iosm->debug && (stage & IOSM_SYSCALL))
02465             rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
02466                 iosm->lpath, iosm->path, (rc < 0 ? strerror(errno) : ""));
02467         if (rc < 0)     rc = IOSMERR_SYMLINK_FAILED;
02468         break;
02469     case IOSM_LINK:
02470         rc = Link(iosm->opath, iosm->path);
02471         if (iosm->debug && (stage & IOSM_SYSCALL))
02472             rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", cur,
02473                 iosm->opath, iosm->path, (rc < 0 ? strerror(errno) : ""));
02474         if (rc < 0)     rc = IOSMERR_LINK_FAILED;
02475         break;
02476     case IOSM_MKFIFO:
02477         rc = Mkfifo(iosm->path, (st->st_mode & 07777));
02478         if (iosm->debug && (stage & IOSM_SYSCALL))
02479             rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", cur,
02480                 iosm->path, (unsigned)(st->st_mode & 07777),
02481                 (rc < 0 ? strerror(errno) : ""));
02482         if (rc < 0)     rc = IOSMERR_MKFIFO_FAILED;
02483         break;
02484     case IOSM_MKNOD:
02485         /*@-unrecog -portability @*/ /* FIX: check S_IFIFO or dev != 0 */
02486         rc = Mknod(iosm->path, (st->st_mode & ~07777), st->st_rdev);
02487         /*@=unrecog =portability @*/
02488         if (iosm->debug && (stage & IOSM_SYSCALL))
02489             rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n", cur,
02490                 iosm->path, (unsigned)(st->st_mode & ~07777),
02491                 (unsigned)st->st_rdev,
02492                 (rc < 0 ? strerror(errno) : ""));
02493         if (rc < 0)     rc = IOSMERR_MKNOD_FAILED;
02494         break;
02495     case IOSM_LSTAT:
02496         rc = Lstat(iosm->path, ost);
02497         if (iosm->debug && (stage & IOSM_SYSCALL) && rc && errno != ENOENT)
02498             rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", cur,
02499                 iosm->path, (rc < 0 ? strerror(errno) : ""));
02500         if (rc < 0) {
02501             rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_LSTAT_FAILED);
02502             memset(ost, 0, sizeof(*ost));       /* XXX s390x hackery */
02503         }
02504         break;
02505     case IOSM_STAT:
02506         rc = Stat(iosm->path, ost);
02507         if (iosm->debug && (stage & IOSM_SYSCALL) && rc && errno != ENOENT)
02508             rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n", cur,
02509                 iosm->path, (rc < 0 ? strerror(errno) : ""));
02510         if (rc < 0) {
02511             rc = (errno == ENOENT ? IOSMERR_ENOENT : IOSMERR_STAT_FAILED);
02512             memset(ost, 0, sizeof(*ost));       /* XXX s390x hackery */
02513         }
02514         break;
02515     case IOSM_READLINK:
02516         /* XXX NUL terminated result in iosm->rdbuf, len in iosm->rdnb. */
02517         rc = Readlink(iosm->path, iosm->rdbuf, iosm->rdsize - 1);
02518         if (iosm->debug && (stage & IOSM_SYSCALL))
02519             rpmlog(RPMLOG_DEBUG, " %8s (%s, rdbuf, %d) %s\n", cur,
02520                 iosm->path, (int)(iosm->rdsize -1), (rc < 0 ? strerror(errno) : ""));
02521         if (rc < 0)     rc = IOSMERR_READLINK_FAILED;
02522         else {
02523             iosm->rdnb = rc;
02524             iosm->rdbuf[iosm->rdnb] = '\0';
02525             rc = 0;
02526         }
02527         break;
02528     case IOSM_CHROOT:
02529         break;
02530 
02531     case IOSM_NEXT:
02532         rc = iosmUNSAFE(iosm, IOSM_HREAD);
02533         if (rc) break;
02534         if (!strcmp(iosm->path, CPIO_TRAILER)) { /* Detect end-of-payload. */
02535             iosm->path = _free(iosm->path);
02536             rc = IOSMERR_HDR_TRAILER;
02537         }
02538         if (!rc)
02539             rc = iosmNext(iosm, IOSM_POS);
02540         break;
02541     case IOSM_EAT:
02542         for (left = st->st_size; left > 0; left -= iosm->rdnb) {
02543             iosm->wrlen = (left > iosm->wrsize ? iosm->wrsize : left);
02544             rc = iosmNext(iosm, IOSM_DREAD);
02545             if (rc)
02546                 /*@loopbreak@*/ break;
02547         }
02548         break;
02549     case IOSM_POS:
02550         left = (iosm->blksize - (fdGetCpioPos(iosm->cfd) % iosm->blksize)) % iosm->blksize;
02551         if (left) {
02552             iosm->wrlen = left;
02553             (void) iosmNext(iosm, IOSM_DREAD);
02554         }
02555         break;
02556     case IOSM_PAD:
02557         left = (iosm->blksize - (fdGetCpioPos(iosm->cfd) % iosm->blksize)) % iosm->blksize;
02558         if (left) {
02559             if (iosm->blksize == 2)
02560                 iosm->rdbuf[0] = '\n';  /* XXX ar(1) pads with '\n' */
02561             else
02562                 memset(iosm->rdbuf, 0, left);
02563             /* XXX DWRITE uses rdnb for I/O length. */
02564             iosm->rdnb = left;
02565             (void) iosmNext(iosm, IOSM_DWRITE);
02566         }
02567         break;
02568     case IOSM_TRAILER:
02569         rc = (*iosm->trailerWrite) (iosm);      /* Write payload trailer. */
02570         break;
02571     case IOSM_HREAD:
02572         rc = iosmNext(iosm, IOSM_POS);
02573         if (!rc)
02574             rc = (*iosm->headerRead) (iosm, st);        /* Read next payload header. */
02575         break;
02576     case IOSM_HWRITE:
02577         rc = (*iosm->headerWrite) (iosm, st);   /* Write next payload header. */
02578         break;
02579     case IOSM_DREAD:
02580         iosm->rdnb = Fread(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->wrlen, iosm->cfd);
02581         if (iosm->debug && (stage & IOSM_SYSCALL))
02582             rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, cfd)\trdnb %d\n",
02583                 cur, (iosm->wrbuf == iosm->wrb ? "wrbuf" : "mmap"),
02584                 (int)iosm->wrlen, (int)iosm->rdnb);
02585         if (iosm->rdnb != iosm->wrlen || Ferror(iosm->cfd))
02586             rc = IOSMERR_READ_FAILED;
02587         if (iosm->rdnb > 0)
02588             fdSetCpioPos(iosm->cfd, fdGetCpioPos(iosm->cfd) + iosm->rdnb);
02589         break;
02590     case IOSM_DWRITE:
02591         iosm->wrnb = Fwrite(iosm->rdbuf, sizeof(*iosm->rdbuf), iosm->rdnb, iosm->cfd);
02592         if (iosm->debug && (stage & IOSM_SYSCALL))
02593             rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, cfd)\twrnb %d\n",
02594                 cur, (iosm->rdbuf == iosm->rdb ? "rdbuf" : "mmap"),
02595                 (int)iosm->rdnb, (int)iosm->wrnb);
02596         if (iosm->rdnb != iosm->wrnb || Ferror(iosm->cfd))
02597             rc = IOSMERR_WRITE_FAILED;
02598         if (iosm->wrnb > 0)
02599             fdSetCpioPos(iosm->cfd, fdGetCpioPos(iosm->cfd) + iosm->wrnb);
02600         break;
02601 
02602     case IOSM_ROPEN:
02603         iosm->rfd = Fopen(iosm->path, "r.fdio");
02604         if (iosm->rfd == NULL || Ferror(iosm->rfd)) {
02605             if (iosm->rfd != NULL)      (void) iosmNext(iosm, IOSM_RCLOSE);
02606             iosm->rfd = NULL;
02607             rc = IOSMERR_OPEN_FAILED;
02608             break;
02609         }
02610         if (iosm->debug && (stage & IOSM_SYSCALL))
02611             rpmlog(RPMLOG_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
02612                 iosm->path, iosm->rfd, iosm->rdbuf);
02613         break;
02614     case IOSM_READ:
02615         iosm->rdnb = Fread(iosm->rdbuf, sizeof(*iosm->rdbuf), iosm->rdlen, iosm->rfd);
02616         if (iosm->debug && (stage & IOSM_SYSCALL))
02617             rpmlog(RPMLOG_DEBUG, " %8s (rdbuf, %d, rfd)\trdnb %d\n",
02618                 cur, (int)iosm->rdlen, (int)iosm->rdnb);
02619         if (iosm->rdnb != iosm->rdlen || Ferror(iosm->rfd))
02620             rc = IOSMERR_READ_FAILED;
02621         break;
02622     case IOSM_RCLOSE:
02623         if (iosm->rfd != NULL) {
02624             if (iosm->debug && (stage & IOSM_SYSCALL))
02625                 rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->rfd);
02626             (void) rpmswAdd(&iosm->op_digest,
02627                         fdstat_op(iosm->rfd, FDSTAT_DIGEST));
02628             (void) Fclose(iosm->rfd);
02629             errno = saveerrno;
02630         }
02631         iosm->rfd = NULL;
02632         break;
02633     case IOSM_WOPEN:
02634         iosm->wfd = Fopen(iosm->path, "w.fdio");
02635         if (iosm->wfd == NULL || Ferror(iosm->wfd)) {
02636             if (iosm->wfd != NULL)      (void) iosmNext(iosm, IOSM_WCLOSE);
02637             iosm->wfd = NULL;
02638             rc = IOSMERR_OPEN_FAILED;
02639         }
02640         if (iosm->debug && (stage & IOSM_SYSCALL))
02641             rpmlog(RPMLOG_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
02642                 iosm->path, iosm->wfd, iosm->wrbuf);
02643         break;
02644     case IOSM_WRITE:
02645         iosm->wrnb = Fwrite(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->rdnb, iosm->wfd);
02646         if (iosm->debug && (stage & IOSM_SYSCALL))
02647             rpmlog(RPMLOG_DEBUG, " %8s (wrbuf, %d, wfd)\twrnb %d\n",
02648                 cur, (int)iosm->rdnb, (int)iosm->wrnb);
02649         if (iosm->rdnb != iosm->wrnb || Ferror(iosm->wfd))
02650             rc = IOSMERR_WRITE_FAILED;
02651         break;
02652     case IOSM_WCLOSE:
02653         if (iosm->wfd != NULL) {
02654             if (iosm->debug && (stage & IOSM_SYSCALL))
02655                 rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->wfd);
02656             (void) rpmswAdd(&iosm->op_digest,
02657                         fdstat_op(iosm->wfd, FDSTAT_DIGEST));
02658             (void) Fclose(iosm->wfd);
02659             errno = saveerrno;
02660         }
02661         iosm->wfd = NULL;
02662         break;
02663 
02664     default:
02665         break;
02666     }
02667 
02668     if (!(stage & IOSM_INTERNAL)) {
02669         iosm->rc = (rc == IOSMERR_HDR_TRAILER ? 0 : rc);
02670     }
02671     return rc;
02672 }
02673 /*@=compmempass@*/
02674 
02675 #define IOSM_SKIPPING(_a)       \
02676     ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR)
02677 
02678 int iosmFileActionSkipped(iosmFileAction action)
02679 {
02680     return IOSM_SKIPPING(action);
02681 }
02682 
02683 /*@observer@*/ const char * iosmFileActionString(iosmFileAction a)
02684 {
02685     switch (a) {
02686     case FA_UNKNOWN:    return "unknown";
02687     case FA_CREATE:     return "create";
02688     case FA_COPYOUT:    return "copyout";
02689     case FA_COPYIN:     return "copyin";
02690     case FA_BACKUP:     return "backup";
02691     case FA_SAVE:       return "save";
02692     case FA_SKIP:       return "skip";
02693     case FA_ALTNAME:    return "altname";
02694     case FA_ERASE:      return "erase";
02695     case FA_SKIPNSTATE: return "skipnstate";
02696     case FA_SKIPNETSHARED: return "skipnetshared";
02697     case FA_SKIPCOLOR:  return "skipcolor";
02698     default:            return "???";
02699     }
02700     /*@notreached@*/
02701 }
02702 
02703 /*@observer@*/ const char * iosmFileStageString(iosmFileStage a) {
02704     switch(a) {
02705     case IOSM_UNKNOWN:  return "unknown";
02706 
02707     case IOSM_PKGINSTALL:return "INSTALL";
02708     case IOSM_PKGERASE: return "ERASE";
02709     case IOSM_PKGBUILD: return "BUILD";
02710     case IOSM_PKGCOMMIT:        return "COMMIT";
02711     case IOSM_PKGUNDO:  return "UNDO";
02712 
02713     case IOSM_CREATE:   return "create";
02714     case IOSM_INIT:     return "init";
02715     case IOSM_MAP:      return "map";
02716     case IOSM_MKDIRS:   return "mkdirs";
02717     case IOSM_RMDIRS:   return "rmdirs";
02718     case IOSM_PRE:      return "pre";
02719     case IOSM_PROCESS:  return "process";
02720     case IOSM_POST:     return "post";
02721     case IOSM_MKLINKS:  return "mklinks";
02722     case IOSM_NOTIFY:   return "notify";
02723     case IOSM_UNDO:     return "undo";
02724     case IOSM_FINI:     return "fini";
02725     case IOSM_COMMIT:   return "commit";
02726     case IOSM_DESTROY:  return "destroy";
02727     case IOSM_VERIFY:   return "verify";
02728 
02729     case IOSM_UNLINK:   return "Unlink";
02730     case IOSM_RENAME:   return "Rename";
02731     case IOSM_MKDIR:    return "Mkdir";
02732     case IOSM_RMDIR:    return "Rmdir";
02733     case IOSM_LSETFCON: return "lsetfcon";
02734     case IOSM_CHOWN:    return "Chown";
02735     case IOSM_LCHOWN:   return "Lchown";
02736     case IOSM_CHMOD:    return "Chmod";
02737     case IOSM_UTIME:    return "Utime";
02738     case IOSM_SYMLINK:  return "Symlink";
02739     case IOSM_LINK:     return "Link";
02740     case IOSM_MKFIFO:   return "Mkfifo";
02741     case IOSM_MKNOD:    return "Mknod";
02742     case IOSM_LSTAT:    return "Lstat";
02743     case IOSM_STAT:     return "Stat";
02744     case IOSM_READLINK: return "Readlink";
02745     case IOSM_CHROOT:   return "Chroot";
02746 
02747     case IOSM_NEXT:     return "next";
02748     case IOSM_EAT:      return "eat";
02749     case IOSM_POS:      return "pos";
02750     case IOSM_PAD:      return "pad";
02751     case IOSM_TRAILER:  return "trailer";
02752     case IOSM_HREAD:    return "hread";
02753     case IOSM_HWRITE:   return "hwrite";
02754     case IOSM_DREAD:    return "Fread";
02755     case IOSM_DWRITE:   return "Fwrite";
02756 
02757     case IOSM_ROPEN:    return "Fopen";
02758     case IOSM_READ:     return "Fread";
02759     case IOSM_RCLOSE:   return "Fclose";
02760     case IOSM_WOPEN:    return "Fopen";
02761     case IOSM_WRITE:    return "Fwrite";
02762     case IOSM_WCLOSE:   return "Fclose";
02763 
02764     default:            return "???";
02765     }
02766     /*@noteached@*/
02767 }
02768 
02769 char * iosmStrerror(int rc)
02770 {
02771     char msg[256];
02772     char *s;
02773     int l, myerrno = errno;
02774 
02775     strcpy(msg, "cpio: ");
02776     switch (rc) {
02777     default:
02778         s = msg + strlen(msg);
02779         sprintf(s, _("(error 0x%x)"), (unsigned)rc);
02780         s = NULL;
02781         break;
02782     case IOSMERR_BAD_MAGIC:     s = _("Bad magic");             break;
02783     case IOSMERR_BAD_HEADER:    s = _("Bad/unreadable header"); break;
02784 
02785     case IOSMERR_OPEN_FAILED:   s = "open";     break;
02786     case IOSMERR_CHMOD_FAILED:  s = "chmod";    break;
02787     case IOSMERR_CHOWN_FAILED:  s = "chown";    break;
02788     case IOSMERR_WRITE_FAILED:  s = "write";    break;
02789     case IOSMERR_UTIME_FAILED:  s = "utime";    break;
02790     case IOSMERR_UNLINK_FAILED: s = "unlink";   break;
02791     case IOSMERR_RENAME_FAILED: s = "rename";   break;
02792     case IOSMERR_SYMLINK_FAILED: s = "symlink"; break;
02793     case IOSMERR_STAT_FAILED:   s = "stat";     break;
02794     case IOSMERR_LSTAT_FAILED:  s = "lstat";    break;
02795     case IOSMERR_MKDIR_FAILED:  s = "mkdir";    break;
02796     case IOSMERR_RMDIR_FAILED:  s = "rmdir";    break;
02797     case IOSMERR_MKNOD_FAILED:  s = "mknod";    break;
02798     case IOSMERR_MKFIFO_FAILED: s = "mkfifo";   break;
02799     case IOSMERR_LINK_FAILED:   s = "link";     break;
02800     case IOSMERR_READLINK_FAILED: s = "readlink";       break;
02801     case IOSMERR_READ_FAILED:   s = "read";     break;
02802     case IOSMERR_COPY_FAILED:   s = "copy";     break;
02803     case IOSMERR_LSETFCON_FAILED: s = "lsetfilecon";    break;
02804 
02805     case IOSMERR_HDR_SIZE:      s = _("Header size too big");   break;
02806     case IOSMERR_UNKNOWN_FILETYPE: s = _("Unknown file type");  break;
02807     case IOSMERR_MISSING_HARDLINK: s = _("Missing hard link(s)"); break;
02808     case IOSMERR_DIGEST_MISMATCH: s = _("File digest mismatch");        break;
02809     case IOSMERR_INTERNAL:      s = _("Internal error");        break;
02810     case IOSMERR_UNMAPPED_FILE: s = _("Archive file not in header"); break;
02811     case IOSMERR_ENOENT:        s = strerror(ENOENT); break;
02812     case IOSMERR_ENOTEMPTY:     s = strerror(ENOTEMPTY); break;
02813     }
02814 
02815     l = sizeof(msg) - strlen(msg) - 1;
02816     if (s != NULL) {
02817         if (l > 0) strncat(msg, s, l);
02818         l -= strlen(s);
02819     }
02820     if ((rc & IOSMERR_CHECK_ERRNO) && myerrno) {
02821         s = _(" failed - ");
02822         if (l > 0) strncat(msg, s, l);
02823         l -= strlen(s);
02824         if (l > 0) strncat(msg, strerror(myerrno), l);
02825     }
02826     return xstrdup(msg);
02827 }