rpm 5.2.1

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

- File List
- Globals

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 }