RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  j...@rpm5.org
  Module: rpm                              Date:   17-Apr-2017 20:19:08
  Branch: rpm-5_4                          Handle: 2017041718190701

  Modified files:           (Branch: rpm-5_4)
    rpm                     CHANGES configure.ac
    rpm/lib                 fsm.c rpmts.c rpmts.h
    rpm/rpmdb               librpmdb.vers pkgio.c
    rpm/rpmio               iosm.c iosm.h librpmio.vers rpmio.c rpmio.h
                            rpmio_internal.h rpmrpc.c

  Log:
    - rpmio: add fallocate+fdatasync+fadvise+fsync.

  Summary:
    Revision    Changes     Path
    1.3501.2.532+1  -0      rpm/CHANGES
    2.472.2.160 +2  -1      rpm/configure.ac
    2.193.4.13  +29 -13     rpm/lib/fsm.c
    2.188.2.20  +4  -1      rpm/lib/rpmts.c
    2.134.2.10  +12 -3      rpm/lib/rpmts.h
    1.91.2.5    +1  -0      rpm/rpmdb/librpmdb.vers
    1.121.2.28  +9  -0      rpm/rpmdb/pkgio.c
    1.43.2.10   +87 -27     rpm/rpmio/iosm.c
    1.18.4.5    +6  -1      rpm/rpmio/iosm.h
    2.199.2.66  +13 -0      rpm/rpmio/librpmio.vers
    1.230.2.39  +189 -3     rpm/rpmio/rpmio.c
    1.97.2.10   +65 -0      rpm/rpmio/rpmio.h
    2.127.2.8   +101 -46    rpm/rpmio/rpmio_internal.h
    2.99.2.6    +347 -111   rpm/rpmio/rpmrpc.c
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: rpm/CHANGES
  ============================================================================
  $ cvs diff -u -r1.3501.2.531 -r1.3501.2.532 CHANGES
  --- rpm/CHANGES       11 Apr 2017 17:36:58 -0000      1.3501.2.531
  +++ rpm/CHANGES       17 Apr 2017 18:19:07 -0000      1.3501.2.532
  @@ -1,4 +1,5 @@
   5.4.17 -> 5.4.18:
  +    - jbj: rpmio: add fallocate+fdatasync+fadvise+fsync.
       - jbj: install: use clock_gettime/gettimeofday/time for *.rpm timestamps.
       - jbj: build: add usecs to RPMTAG_BUILDTIME/RPMTAG_COOKIE.
       - jbj: header: minor optimization for headerGet().
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/configure.ac
  ============================================================================
  $ cvs diff -u -r2.472.2.159 -r2.472.2.160 configure.ac
  --- rpm/configure.ac  13 Apr 2017 15:19:23 -0000      2.472.2.159
  +++ rpm/configure.ac  17 Apr 2017 18:19:07 -0000      2.472.2.160
  @@ -686,6 +686,7 @@
   AC_ARG_ENABLE(build-sanitize-address,
       AS_HELP_STRING([--enable-build-sanitize-address], [build RPM 
instrumented for -fsanitize=address]), [dnl
       if test ".$enableval" = .yes; then
  +        export ASAN_OPTIONS="detect_leaks=0"
           if test \( ".`$CC --version 2>&1 | grep 'GCC'`" != . \); then
               rpm_CPPFLAGS_ADD([-fsanitize=address], [CPPFLAGS])
               rpm_LDFLAGS_ADD([-fsanitize=address], [LDFLAGS])
  @@ -1583,7 +1584,7 @@
       mkdtemp mkfifo mkstemp msync mtrace munmap nl_langinfo dnl
       pathconf posix_fadvise posix_fallocate posix_madvise posix_memalign dnl
       posix_memalign posix_mem_offset posix_typed_mem_open dnl
  -    pow putenv realpath regcomp rmdir rpmatch __secure_getenv secure_getenv 
dnl
  +    pow prctl putenv realpath regcomp rmdir rpmatch __secure_getenv 
secure_getenv dnl
       select sendfile setattrlist setenv setmode setns setxattr dnl
       sigaction sigaddset sigdelset sigemptyset sighold sigpause dnl
       sigprocmask sigrelse sigsuspend setlocale socket splice sqrt dnl
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/lib/fsm.c
  ============================================================================
  $ cvs diff -u -r2.193.4.12 -r2.193.4.13 fsm.c
  --- rpm/lib/fsm.c     6 Jul 2016 13:20:42 -0000       2.193.4.12
  +++ rpm/lib/fsm.c     17 Apr 2017 18:19:07 -0000      2.193.4.13
  @@ -147,7 +147,7 @@
       if (iter) {
        iter->fi = rpmfiUnlink(iter->fi, "mapIterator");
   /*@-internalglobs@*/ /* XXX rpmswExit() */
  -     (void)rpmtsFree(iter->ts); 
  +     (void) rpmtsFree(iter->ts); 
        iter->ts = NULL;
   /*@=internalglobs@*/
       }
  @@ -557,6 +557,7 @@
   IOSM_t newFSM(void)
   {
       IOSM_t fsm = (IOSM_t) xcalloc(1, sizeof(*fsm));
  +    fsm->stats = xcalloc(1, sizeof(*fsm->stats));
       return fsm;
   }
   
  @@ -572,6 +573,7 @@
        fsm->dnlx = _free(fsm->dnlx);
        fsm->ldn = _free(fsm->ldn);
        fsm->iter = mapFreeIterator(fsm->iter);
  +     fsm->stats = _free(fsm->stats);
       }
       return _free(fsm);
   }
  @@ -764,10 +766,15 @@
       if (!rc)
        rc = fsmUNSAFE(fsm, IOSM_DESTROY);
   
  -    (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST), 
&fsm->op_digest);
  +    /* XXX eliminate when ts->stats is printed. */
  +    (void) rpmswAdd(rpmtsOp(fsmGetTs(fsm), RPMTS_OP_DIGEST), 
&fsm->stats->ops[FDSTAT_DIGEST]);
  +    FDSTAT_t stats = (FDSTAT_t) rpmtsStats(fsmGetTs(fsm));
  +    if (stats)
  +    for (int opx = 0; opx < FDSTAT_MAX; opx++)
  +        (void) rpmswAdd(&stats->ops[opx], &fsm->stats->ops[opx]);
   
       fsm->lmtab = _free(fsm->lmtab);
  -    (void)rpmtsFree(fsm->iter->ts); 
  +    (void) rpmtsFree(fsm->iter->ts); 
       fsm->iter->ts = NULL;
       fsm->iter = mapFreeIterator(fsm->iter);
       if (fsm->cfd != NULL) {
  @@ -1023,8 +1030,10 @@
            (void) fsmNext(fsm, IOSM_NOTIFY);
       }
   
  -#ifdef       DYING
  -/* Measurements from installing kernel-source package:
  +    (void) Fflush(fsm->wfd);
  +
  +#ifdef       REFERENCE
  +/* Measurements from installing kernel-source package (circa 2012):
    * +fsync
    *   total:               1      0.000000 MB    640.854524 secs
    * +fdatasync
  @@ -1039,7 +1048,6 @@
        void * digest = NULL;
        int asAscii = (fsm->digest == NULL ? 1 : 0);
   
  -     (void) Fflush(fsm->wfd);
        fdFiniDigest(fsm->wfd, fsm->fdigestalgo, &digest, NULL, asAscii);
   
        if (digest == NULL) {
  @@ -1128,7 +1136,7 @@
        void * mapped = (void *)-1;
        size_t nmapped = 0;
        /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
  -     int use_mmap = (st->st_size <= 0x07ffffff);
  +     int use_mmap = (st->st_size > 0 && st->st_size < _iosm_maxsize);
   #endif
   
        rc = fsmNext(fsm, IOSM_ROPEN);
  @@ -1776,10 +1784,18 @@
        fsm->rdbuf = fsm->rdb = _free(fsm->rdb);
        fsm->wrbuf = fsm->wrb = _free(fsm->wrb);
        if (fsm->goal == IOSM_PKGINSTALL || fsm->goal == IOSM_PKGBUILD) {
  -         fsm->rdsize = 16 * BUFSIZ;
  -         fsm->rdbuf = fsm->rdb = (char *) xmalloc(fsm->rdsize);
  -         fsm->wrsize = 16 * BUFSIZ;
  -         fsm->wrbuf = fsm->wrb = (char *) xmalloc(fsm->wrsize);
  +         fsm->rdsize = _iosm_bufsize;
  +         fsm->wrsize = _iosm_bufsize;
  +#if defined(HAVE_POSIX_MEMALIGN)
  +         /* XXX ensure buffers are aligned on page boundary (O_DIRECT?) */
  +         rc = posix_memalign((void **)&fsm->rdb, BUFSIZ, fsm->rdsize);
  +         rc = posix_memalign((void **)&fsm->wrb, BUFSIZ, fsm->wrsize);
  +#else
  +         fsm->rdb = (char *) xmalloc(fsm->rdsize);
  +         fsm->wrb = (char *) xmalloc(fsm->wrsize);
  +#endif
  +         fsm->rdbuf = fsm->rdb;
  +         fsm->wrbuf = fsm->wrb;
        }
   
        fsm->mkdirsdone = 0;
  @@ -2322,7 +2338,7 @@
        rc = rpmlioUnlink(rpmtsGetRdb(fsmGetTs(fsm)), fn, mode, b, blen, d, 
dlen, dalgo);
        if (fd != NULL) {
   /*@-observertrans@*/ /* FIX: b should be initialized to NULL, not "" */
  -         (void)munmap(b, blen);
  +         (void) munmap(b, blen);
   /*@=observertrans@*/
            (void) Fclose(fd);
            fd = NULL;
  @@ -2348,7 +2364,7 @@
        mode = sb.st_mode;
        rc = rpmlioRename(rpmtsGetRdb(fsmGetTs(fsm)), ofn, fn, mode, b, blen, 
d, dlen, dalgo);
        if (fd != NULL) {
  -         (void)munmap(b, blen);
  +         (void) munmap(b, blen);
            (void) Fclose(fd);
            fd = NULL;
        }
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/lib/rpmts.c
  ============================================================================
  $ cvs diff -u -r2.188.2.19 -r2.188.2.20 rpmts.c
  --- rpm/lib/rpmts.c   13 Apr 2017 15:21:21 -0000      2.188.2.19
  +++ rpm/lib/rpmts.c   17 Apr 2017 18:19:07 -0000      2.188.2.20
  @@ -4,7 +4,7 @@
    */
   #include "system.h"
   
  -#include <rpmio.h>
  +#include <rpmio_internal.h>  /* XXX sizeof(*ts->stats) */
   #include <rpmiotypes.h>              /* XXX fnpyKey */
   #include <rpmlog.h>
   #include <rpmcb.h>           /* XXX rpmIsVerbose() */
  @@ -792,6 +792,7 @@
   
       if (_rpmts_stats)
        rpmtsPrintStats(ts);
  +    ts->stats = _free(ts->stats);
   
       if (_rpmts_macros) {
        const char ** av = NULL;
  @@ -1618,5 +1619,7 @@
       /* Set autorollback goal to the end of time. */
       ts->arbgoal = 0xffffffff;
   
  +    ts->stats = xcalloc(1, sizeof(*ts->stats));
  +
       return rpmtsLink(ts, "tsCreate");
   }
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/lib/rpmts.h
  ============================================================================
  $ cvs diff -u -r2.134.2.9 -r2.134.2.10 rpmts.h
  --- rpm/lib/rpmts.h   11 Apr 2017 17:36:59 -0000      2.134.2.9
  +++ rpm/lib/rpmts.h   17 Apr 2017 18:19:07 -0000      2.134.2.10
  @@ -278,6 +278,7 @@
       void * hkp;                      /*!< Pubkey validation container. */
   
       struct rpmop_s ops[RPMTS_OP_MAX];
  +    FDSTAT_t stats;          /*!< I/O stats. */
   
       pgpDig dig;                      /*!< Current signature/pubkey 
parameters. */
   
  @@ -674,7 +675,7 @@
   rpmuint32_t rpmtsGetTid(rpmts ts)
        RPM_GNUC_PURE;
   rpmuint32_t * rpmtsGetTid2(rpmts ts)
  -     RPM_GNUC_PURE;
  +     RPM_GNUC_CONST;
   
   /** \ingroup rpmts
    * Set transaction id, i.e. transaction time stamp.
  @@ -909,15 +910,23 @@
   rpmuint32_t rpmtsSetPrefColor(rpmts ts, rpmuint32_t color);
   
   /** \ingroup rpmts
  - * Retrieve operation timestamp from a transaction set.
  + * Retrieve operation stats from a transaction set.
    * @param ts         transaction set
    * @param opx                operation timestamp index
  - * @return           pointer to operation timestamp.
  + * @return           pointer to operation stats.
    */
   rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
        RPM_GNUC_CONST;
   
   /** \ingroup rpmts
  + * Retrieve operation I/O stats from a transaction set.
  + * @param ts         transaction set
  + * @return           pointer to I/O operation stats.
  + */
  +void * rpmtsStats(rpmts ts)
  +     RPM_GNUC_CONST;
  +
  +/** \ingroup rpmts
    * Set transaction notify callback function and argument.
    *
    * @warning This call must be made before rpmtsRun() for
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmdb/librpmdb.vers
  ============================================================================
  $ cvs diff -u -r1.91.2.4 -r1.91.2.5 librpmdb.vers
  --- rpm/rpmdb/librpmdb.vers   27 Jun 2016 03:08:21 -0000      1.91.2.4
  +++ rpm/rpmdb/librpmdb.vers   17 Apr 2017 18:19:07 -0000      1.91.2.5
  @@ -249,6 +249,7 @@
       rpmtsGetRdb;
       rpmtsOp;
       rpmtsPubkey;
  +    rpmtsStats;
       rpmtxnAbort;
       rpmtxnBegin;
       rpmtxnCheckpoint;
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmdb/pkgio.c
  ============================================================================
  $ cvs diff -u -r1.121.2.27 -r1.121.2.28 pkgio.c
  --- rpm/rpmdb/pkgio.c 10 May 2016 17:05:14 -0000      1.121.2.27
  +++ rpm/rpmdb/pkgio.c 17 Apr 2017 18:19:07 -0000      1.121.2.28
  @@ -120,6 +120,15 @@
       return op;
   }
   
  +void * rpmtsStats(rpmts ts)
  +{
  +    void * stats = NULL;
  +
  +    if (ts != NULL && ts->stats != NULL)
  +     stats = (void *) ts->stats;
  +    return stats;
  +}
  +
   pgpDigParams rpmtsPubkey(const rpmts ts)
   {
       return pgpGetPubkey(rpmtsDig(ts));
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/iosm.c
  ============================================================================
  $ cvs diff -u -r1.43.2.9 -r1.43.2.10 iosm.c
  --- rpm/rpmio/iosm.c  5 Jul 2016 14:46:57 -0000       1.43.2.9
  +++ rpm/rpmio/iosm.c  17 Apr 2017 18:19:08 -0000      1.43.2.10
  @@ -79,6 +79,12 @@
   int _iosm_threads = 0;
   /*@=exportheadervar@*/
   
  +/* maximum pre-fallocate and mmap size. */
  +off_t _iosm_maxsize = 128 * 1024 * 1024;
  +
  +/* size of R/W buffers */
  +size_t _iosm_bufsize = 32 * BUFSIZ;
  +
   /*@-redecl@*/
   int (*_iosmNext) (IOSM_t iosm, iosmFileStage nstage)
           /*@modifies iosm @*/ = &iosmNext;
  @@ -579,6 +585,7 @@
   IOSM_t newIOSM(void)
   {
       IOSM_t iosm = (IOSM_t) xcalloc(1, sizeof(*iosm));
  +    iosm->stats = xcalloc(1, sizeof(*iosm->stats));
       return iosm;
   }
   
  @@ -594,6 +601,7 @@
        iosm->dnlx = _free(iosm->dnlx);
        iosm->ldn = _free(iosm->ldn);
        iosm->iter = (IOSMI_t) mapFreeIterator((IOSMI_t)iosm->iter);
  +     iosm->stats = _free(iosm->stats);
       }
       return _free(iosm);
   }
  @@ -817,8 +825,14 @@
   
       if (iosm->iter != NULL) {
   #if defined(_USE_RPMTS)
  +     /* XXX eliminate when ts->stats is printed. */
        (void) rpmswAdd(rpmtsOp(iosmGetTs(iosm), RPMTS_OP_DIGEST),
  -                     &iosm->op_digest);
  +                     &iosm->stats->ops[FDSTAT_DIGEST]);
  +     FDSTAT_t stats = (FDSTAT_t) rpmtsStats(iosmGetTs(iosm));
  +     if (stats)
  +     for (int opx = 0; opx < FDSTAT_MAX; opx++)
  +         (void) rpmswAdd(&stats->ops[opx], &iosm->stats->ops[opx]);
  +
        (void)rpmtsFree(iosm->iter->ts); 
   #endif
        iosm->iter->ts = NULL;
  @@ -1040,12 +1054,21 @@
       const struct stat * st = &iosm->sb;
       size_t left = (size_t) st->st_size;
       int rc = 0;
  -    int xx;
   
       rc = iosmNext(iosm, IOSM_WOPEN);
       if (rc)
        goto exit;
   
  +    if (fdGetFlags(iosm->wfd) & RPMFD_FLAG_FALLOCATE) {
  +#if defined(HAVE_POSIX_FALLOCATE) || defined(HAVE_FALLOCATE)
  +     if (st->st_size > 0) {
  +         rc = Fallocate(iosm->wfd, 0, st->st_size);
  +         if (rc)
  +             goto exit;
  +     }
  +#endif
  +    }
  +
       if (st->st_size > 0 && (iosm->fdigest != NULL || iosm->digest != NULL))
        fdInitDigest(iosm->wfd, (pgpHashAlgo)iosm->fdigestalgo, 0);
   
  @@ -1067,13 +1090,30 @@
            (void) iosmNext(iosm, IOSM_NOTIFY);
       }
   
  -    xx = fsync(Fileno(iosm->wfd));
  +    (void) Fflush(iosm->wfd);
  +
  +    if (fdGetFlags(iosm->wfd) & RPMFD_FLAG_FSYNC) {
  +#if defined(HAVE_FDATASYNC)
  +     rc = Fdatasync(iosm->wfd);
  +     if (rc)
  +         goto exit;
  +#endif
  +#if defined(POSIX_FADV_DONTNEED)
  +     rc = Fadvise(iosm->wfd, 0, 0, POSIX_FADV_DONTNEED);
  +     if (rc)
  +         goto exit;
  +#endif  
  +#if defined(HAVE_FSYNC)
  +     rc = Fsync(iosm->wfd);
  +     if (rc)
  +         goto exit;
  +#endif
  +    }
   
       if (st->st_size > 0 && (iosm->fdigest || iosm->digest)) {
        void * digest = NULL;
        int asAscii = (iosm->digest == NULL ? 1 : 0);
   
  -     (void) Fflush(iosm->wfd);
        fdFiniDigest(iosm->wfd, (pgpHashAlgo)iosm->fdigestalgo, &digest, NULL, 
asAscii);
   
        if (digest == NULL) {
  @@ -1160,8 +1200,7 @@
        char * rdbuf = NULL;
        void * mapped = (void *)-1;
        size_t nmapped = 0;
  -     /* XXX 128 Mb resource cap for top(1) scrutiny, MADV_DONTNEED better. */
  -     int use_mmap = (st->st_size <= 0x07ffffff);
  +     int use_mmap = (st->st_size > 0 && st->st_size < _iosm_maxsize);
   #endif
   
        rc = iosmNext(iosm, IOSM_ROPEN);
  @@ -1556,7 +1595,7 @@
   #if defined(_USE_RPMSX)
                    /* XXX FIXME? only new dir will have context set. */
                    /* Get file security context from patterns. */
  -                 if (!fsm->nofcontexts) {
  +                 if (!iosm->nofcontexts) {
                        iosm->fcontext =
                                rpmsxMatch(NULL, iosm->path, st->st_mode);
                        if (iosm->fcontext != NULL)
  @@ -1815,10 +1854,18 @@
        iosm->rdbuf = iosm->rdb = _free(iosm->rdb);
        iosm->wrbuf = iosm->wrb = _free(iosm->wrb);
        if (iosm->goal == IOSM_PKGINSTALL || iosm->goal == IOSM_PKGBUILD) {
  -         iosm->rdsize = 16 * BUFSIZ;
  -         iosm->rdbuf = iosm->rdb = (char *) xmalloc(iosm->rdsize);
  -         iosm->wrsize = 16 * BUFSIZ;
  -         iosm->wrbuf = iosm->wrb = (char *) xmalloc(iosm->wrsize);
  +         iosm->rdsize = _iosm_bufsize;
  +         iosm->wrsize = _iosm_bufsize;
  +#if defined(HAVE_POSIX_MEMALIGN)
  +         /* XXX ensure buffers are aligned on page boundary (O_DIRECT?) */
  +         rc = posix_memalign((void **)&iosm->rdb, BUFSIZ, iosm->rdsize);
  +         rc = posix_memalign((void **)&iosm->wrb, BUFSIZ, iosm->wrsize);
  +#else
  +         iosm->rdb = (char *) xmalloc(iosm->rdsize);
  +         iosm->wrb = (char *) xmalloc(iosm->wrsize);
  +#endif 
  +         iosm->rdbuf = iosm->rdb;
  +         iosm->wrbuf = iosm->wrb;
        }
   
        iosm->mkdirsdone = 0;
  @@ -2602,16 +2649,19 @@
        break;
   
       case IOSM_ROPEN:
  -     iosm->rfd = Fopen(iosm->path, "r.fdio");
  -     if (iosm->rfd == NULL || Ferror(iosm->rfd)) {
  +     iosm->rfd = Fopen(iosm->path, "rb+em.fdio");
  +     if (iosm->rfd == NULL || Ferror(iosm->rfd)
  +#if defined(POSIX_FADV_WILLNEED)
  +      || Fadvise(iosm->rfd, 0, 0, POSIX_FADV_WILLNEED)
  +#endif
  +     ) {
            if (iosm->rfd != NULL)      (void) iosmNext(iosm, IOSM_RCLOSE);
            iosm->rfd = NULL;
  +         iosm->rfdno = -1;                   /* XXX */
            rc = IOSMERR_OPEN_FAILED;
            break;
        }
  -#if defined(POSIX_FADV_WILLNEED)
  -     (void) Fadvise(iosm->rfd, 0, 0, POSIX_FADV_WILLNEED);
  -#endif
  +     iosm->rfdno = Fileno(iosm->rfd);        /* XXX */
        if (iosm->debug && (stage & IOSM_SYSCALL))
            rpmlog(RPMLOG_DEBUG, " %8s (%s, \"r\") rfd %p rdbuf %p\n", cur,
                iosm->path, iosm->rfd, iosm->rdbuf);
  @@ -2628,27 +2678,37 @@
        if (iosm->rfd != NULL) {
            if (iosm->debug && (stage & IOSM_SYSCALL))
                rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->rfd);
  -         (void) rpmswAdd(&iosm->op_digest,
  -                     fdstat_op(iosm->rfd, FDSTAT_DIGEST));
  +         fdstat_sum(iosm->wfd, iosm->stats);
            (void) Fclose(iosm->rfd);
            errno = saveerrno;
        }
        iosm->rfd = NULL;
  +     iosm->rfdno = -1;                       /* XXX */
        break;
       case IOSM_WOPEN:
  -     iosm->wfd = Fopen(iosm->path, "w.fdio");
  +     iosm->wfd = Fopen(iosm->path, "wb+e.fdio");
        if (iosm->wfd == NULL || Ferror(iosm->wfd)) {
  -         if (iosm->wfd != NULL)      (void) iosmNext(iosm, IOSM_WCLOSE);
  -         iosm->wfd = NULL;
  +         (void) iosmNext(iosm, IOSM_WCLOSE);
            rc = IOSMERR_OPEN_FAILED;
  +         break;
        }
  -#if defined(POSIX_FADV_DONTNEED)
  -     else
  -         (void) Fadvise(iosm->wfd, 0, 0, POSIX_FADV_DONTNEED);
  -#endif
  +     iosm->wfdno = Fileno(iosm->wfd);        /* XXX */
        if (iosm->debug && (stage & IOSM_SYSCALL))
            rpmlog(RPMLOG_DEBUG, " %8s (%s, \"w\") wfd %p wrbuf %p\n", cur,
                iosm->path, iosm->wfd, iosm->wrbuf);
  +
  +     /* Pre-allocate pages to avoid ENOSPC && metadata writes by *sync() */
  +     if (RPMFD_ISSET(iosm->wfd, FALLOCATE)
  +       && (st->st_size > 0 && st->st_size < _iosm_maxsize))
  +     {
  +         rc = Fallocate(iosm->wfd, 0, st->st_size);
  +         if (rc < 0 && errno != ENOSYS) {
  +             rc = iosmNext(iosm, IOSM_WCLOSE);
  +             rc = IOSMERR_OPEN_FAILED;       /* XXX IOSM_ALLOC_FAILED? */
  +             break;
  +         }
  +         rc = 0;
  +     }
        break;
       case IOSM_WRITE:
        iosm->wrnb = Fwrite(iosm->wrbuf, sizeof(*iosm->wrbuf), iosm->rdnb, 
iosm->wfd);
  @@ -2662,12 +2722,12 @@
        if (iosm->wfd != NULL) {
            if (iosm->debug && (stage & IOSM_SYSCALL))
                rpmlog(RPMLOG_DEBUG, " %8s (%p)\n", cur, iosm->wfd);
  -         (void) rpmswAdd(&iosm->op_digest,
  -                     fdstat_op(iosm->wfd, FDSTAT_DIGEST));
  +         fdstat_sum(iosm->wfd, iosm->stats);
            (void) Fclose(iosm->wfd);
            errno = saveerrno;
        }
        iosm->wfd = NULL;
  +     iosm->wfdno = -1;                       /* XXX */
        break;
   
       default:
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/iosm.h
  ============================================================================
  $ cvs diff -u -r1.18.4.4 -r1.18.4.5 iosm.h
  --- rpm/rpmio/iosm.h  27 Sep 2014 15:51:21 -0000      1.18.4.4
  +++ rpm/rpmio/iosm.h  17 Apr 2017 18:19:08 -0000      1.18.4.5
  @@ -21,6 +21,9 @@
   extern int _iosm_debug;
   /*@=exportlocal@*/
   
  +extern off_t _iosm_maxsize;  /* XXX usually 128Mb */
  +extern size_t _iosm_bufsize; /* XXX usually 256Kb (32*BUFSIZ) */
  +
   /**
    * File disposition(s) during package install/erase processing.
    */
  @@ -226,6 +229,7 @@
       FD_t cfd;                        /*!< Payload file handle. */
   /*@relnull@*/
       FD_t rfd;                        /*!<  read: File handle. */
  +    int rfdno;                       /*!<  read: File descriptor. */
   /*@dependent@*/ /*@relnull@*/
       char * rdbuf;            /*!<  read: Buffer. */
   /*@owned@*/ /*@relnull@*/
  @@ -234,6 +238,7 @@
       size_t rdlen;            /*!<  read: Number of bytes requested.*/
       size_t rdnb;             /*!<  read: Number of bytes returned. */
       FD_t wfd;                        /*!< write: File handle. */
  +    int wfdno;                       /*!< write: File descriptor. */
   /*@dependent@*/ /*@relnull@*/
       char * wrbuf;            /*!< write: Buffer. */
   /*@owned@*/ /*@relnull@*/
  @@ -318,7 +323,7 @@
       size_t lmtablen;         /*!< ar(1) no. bytes in lmtab. */
       size_t lmtaboff;         /*!< ar(1) current offset in lmtab. */
   
  -    struct rpmop_s op_digest;        /*!< RPMSW_OP_DIGEST accumulator. */
  +    FDSTAT_t stats;          /*!< FDSTAT accumulator. */
   };
   #endif
   
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/librpmio.vers
  ============================================================================
  $ cvs diff -u -r2.199.2.65 -r2.199.2.66 librpmio.vers
  --- rpm/rpmio/librpmio.vers   6 Mar 2017 17:52:54 -0000       2.199.2.65
  +++ rpm/rpmio/librpmio.vers   17 Apr 2017 18:19:08 -0000      2.199.2.66
  @@ -104,6 +104,7 @@
       _Fclose;
       Fcntl;
       _Fcntl;
  +    Fdatasync;
       fdDup;
       fdFgets;
       fdio;
  @@ -132,12 +133,14 @@
       _Fstat;
       Fstrerror;
       _Fstrerror;
  +    Fsync;
       Ftell;
       ftpCmd;
       _ftp_debug;
       ftpOpen;
       ftpReq;
       ftpStrerror;
  +    Ftruncate;
       _fts_debug;
       Fts_children;
       Fts_close;
  @@ -171,6 +174,8 @@
       htHasEntry;
       _init;
       _iosm_debug;
  +    _iosm_bufsize;
  +    _iosm_maxsize;
       iosmFileActionSkipped;
       iosmFileActionString;
       iosmFileStageString;
  @@ -226,7 +231,12 @@
       _Mkfifo;
       Mknod;
       _Mknod;
  +    Madvise;
  +    Mincore;
  +    Mmap;
       Mount;
  +    Mprotect;
  +    Munmap;
       noLibio;
       _odbc_debug;
       odbcBindCol;
  @@ -881,6 +891,7 @@
       Versionsort;
       Seekdir;
       _Seekdir;
  +    Splice;
       Stat;
       _Stat;
       Symlink;
  @@ -889,6 +900,7 @@
       tarHeaderRead;
       tarHeaderWrite;
       tarTrailerWrite;
  +    Tee;
       Telldir;
       _Telldir;
       ufdClose;
  @@ -921,6 +933,7 @@
       Utimes;
       _Utimes;
       vmefail;
  +    Vmsplice;
       _xar_debug;
       xstrcasecmp;
       xstrncasecmp;
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/rpmio.c
  ============================================================================
  $ cvs diff -u -r1.230.2.38 -r1.230.2.39 rpmio.c
  --- rpm/rpmio/rpmio.c 11 Apr 2017 17:38:06 -0000      1.230.2.38
  +++ rpm/rpmio/rpmio.c 17 Apr 2017 18:19:08 -0000      1.230.2.39
  @@ -518,6 +518,92 @@
       return (int) rc;
   }
   
  +#ifdef       DEBUGGING
  +static size_t mmincore(const char * msg, void * b, size_t nb)
  +{   
  +    size_t cnt = 0; 
  +    size_t pagesize = sysconf(_SC_PAGESIZE);
  +    size_t npages = (nb + pagesize-1)/pagesize;
  +    unsigned char * vec = alloca(npages+1);
  +      
  +    if (msg)
  +     fprintf(stderr, "%s:", msg);
  +    if (Mincore(b, nb, vec) == -1) {
  +     perror("mincore");
  +     goto exit;
  +    }
  +    for (size_t i = 0; i < npages; i++) {
  +     if (!vec[i] & 0x1)
  +         continue;
  +     cnt++;
  +    }
  +  
  +exit:
  +    fprintf(stderr, " %u\n", (unsigned)cnt);
  +    return cnt;
  +}
  +
  +static size_t fmincore(const char * msg, int fdno)
  +{   
  +    size_t cnt = 0;
  +    void * mapped = MAP_FAILED;
  +    size_t nmapped = 0;
  +    struct stat sb;
  +  
  +    if (fstat(fdno, &sb) == -1) {
  +     perror("fstat failed");
  +     goto exit;
  +    }
  +    if (sb.st_size == 0)
  +     goto exit;
  +  
  +    nmapped = sb.st_size;
  +    mapped = mmap(NULL, nmapped, PROT_READ|PROT_WRITE, MAP_SHARED, fdno, 0);
  +    if (mapped == MAP_FAILED) {
  +     perror("fmincore mmap failed");
  +     goto exit;
  +    }
  +  
  +    cnt = mmincore(msg, mapped, nmapped);
  +  
  +    if (munmap(mapped, nmapped) == -1) {
  +     perror("fmincore munmap failed");
  +     goto exit;
  +    }
  +  
  +exit:
  +    return cnt;
  +}
  +#endif
  +
  +static int fdSync(FD_t fd)
  +{
  +    int rc = -2;
  +    int fdno = fdFileno(fd);
  +
  +    if (fdno >= 0 && RPMFD_ISSET(fd, FSYNC)) {
  +     if (RPMFD_ISSET(fd, FDATASYNC)) {
  +         rc = Fdatasync(fd);
  +         if (rc < 0 && errno != ENOSYS)      /* XXX best effort */
  +             goto exit;
  +     }
  +     if (RPMFD_ISSET(fd, FADVISE)) {
  +#if defined(POSIX_FADV_DONTNEED)
  +         rc = Fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
  +#endif  
  +         if (rc < 0 && errno != ENOSYS)      /* XXX best effort */
  +             goto exit;
  +     }
  +     rc = Fsync(fd);
  +     if (rc < 0 && errno != ENOSYS)          /* XXX best effort */
  +         goto exit;
  +    }
  +    rc = 0;
  +
  +exit:
  +    return rc;
  +}
  +
   static int fdClose( /*@only@*/ void * cookie)
        /*@globals errno, fileSystem, systemState, internalState @*/
        /*@modifies errno, fileSystem, systemState, internalState @*/
  @@ -528,8 +614,12 @@
   
       if (cookie == NULL) return -2;
       fd = c2f(cookie);
  -    fdno = fdFileno(fd);
   
  +    /* Perform sync-on-close (if requested). */
  +    if (RPMFD_ISSET(fd, FSYNC))
  +     rc = fdSync(fd);
  +
  +    fdno = fdFileno(fd);
       fdSetFdno(fd, -1);
   
       fdstat_enter(fd, FDSTAT_CLOSE);
  @@ -545,26 +635,99 @@
       fdstat_exit(fd, FDSTAT_CLOSE, rc);
   
   DBGIO(fd, (stderr, "<--\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), 
(unsigned long)rc, fdbg(fd)));
  +    if (!rc && (_rpmio_debug || rpmIsDebug())) fdstat_print(fd, " FDIO", 
stderr);
   
       fd = fdFree(fd, "open (fdClose)");
       return rc;
   }
   
  +static int _oflagmask = (O_RDONLY|O_WRONLY|O_RDWR
  +     /* -- linux */
  +#ifdef       O_APPEND
  +     |O_APPEND
  +#endif
  +#ifdef       O_ASYNC
  +     |O_ASYNC
  +#endif
  +#ifdef       O_CLOEXEC
  +     |O_CLOEXEC
  +#endif
  +#ifdef       O_CREAT
  +     |O_CREAT
  +#endif
  +#ifdef       O_DIRECT
  +     |O_DIRECT
  +#endif
  +#ifdef       O_DIRECTORY
  +     |O_DIRECTORY
  +#endif
  +#ifdef       O_DSYNC
  +     |O_DSYNC
  +#endif
  +#ifdef       O_EXCL
  +     |O_EXCL
  +#endif
  +#ifdef       O_LARGEFILE
  +     |O_LARGEFILE
  +#endif
  +#ifdef       O_NOATIME
  +     |O_NOATIME
  +#endif
  +#ifdef       O_NOCTTY
  +     |O_NOCTTY
  +#endif
  +#ifdef       O_NOFOLLOW
  +     |O_NOFOLLOW
  +#endif
  +#ifdef       O_NONBLOCK
  +     |O_NONBLOCK
  +#endif
  +#ifdef       O_NDELAY
  +     |O_NDELAY
  +#endif
  +#ifdef       O_PATH
  +     |O_PATH
  +#endif
  +#ifdef       O_SYNC
  +     |O_SYNC
  +#endif
  +#ifdef       O_TMPFILE
  +     |O_TMPFILE
  +#endif
  +#ifdef       O_TRUNC
  +     |O_TRUNC
  +#endif
  +     /* -- OS X */
  +#ifdef       O_SHLOCK
  +     |O_SHLOCK
  +#endif
  +#ifdef       O_EXLOCK
  +     |O_EXLOCK
  +#endif
  +#ifdef       O_SYMLINK
  +     |O_SYMLINK
  +#endif
  +#ifdef       O_EVTONLY
  +     |O_EVTONLY
  +#endif
  +    );
  +
   static /*@null@*/ FD_t fdOpen(const char *path, int flags, mode_t mode)
        /*@globals errno, fileSystem, internalState @*/
        /*@modifies errno, fileSystem, internalState @*/
   {
       FD_t fd;
       int fdno;
  +    int oflags = (flags & _oflagmask);
   
  -    fdno = open(path, flags, mode);
  +    fdno = open(path, oflags, mode);
       if (fdno < 0) return NULL;
       if (fcntl(fdno, F_SETFD, FD_CLOEXEC)) {
        (void) close(fdno);
        return NULL;
       }
       fd = fdNew("open (fdOpen)");
  -    fdSetOpen(fd, path, flags, mode);
  +    fdSetOpen(fd, path, oflags, mode);
       fdSetFdno(fd, fdno);
   assert(fd != NULL);
       fd->flags = flags;
  @@ -2668,6 +2831,10 @@
    * - bzopen: 'q' sets verbosity to 0
    * - bzopen: 'v' does verbosity++ (up to 4)
    * - HACK:   '.' terminates, rest is type of I/O
  + * - HACK:   'D' sync (O_DSYNC)
  + * - HACK:   'S' sync (O_SYNC)
  + * - HACK:   'J' fallocate+fdatasync+fadvise+fsync
  + * - HACK:   '?' debug I/O + refcnt
    */
   static inline void cvtfmode (const char *m,
                                /*@out@*/ char *stdio, size_t nstdio,
  @@ -2723,7 +2890,24 @@
            if (--nstdio > 0) *stdio++ = c;
            continue;
            /*@notreached@*/ /*@switchbreak@*/ break;
  +     case 'D':
  +         flags |= O_DSYNC;
  +         goto other;
  +     case 'S':
  +         flags |= O_SYNC;
  +         goto other;
  +     case 'J':
  +         RPMFD_SET(flags, FALLOCATE);
  +         RPMFD_SET(flags, FDATASYNC);
  +         RPMFD_SET(flags, FADVISE);
  +         RPMFD_SET(flags, FSYNC);
  +         goto other;
  +     case '?':
  +         RPMFD_SET(flags, DEBUGIO);
  +         RPMFD_SET(flags, DEBUGREFS);
  +         goto other;
        default:
  +       other:
            if (--nother > 0) *other++ = c;
            continue;
            /*@notreached@*/ /*@switchbreak@*/ break;
  @@ -3048,7 +3232,9 @@
        rc = fd->fps[i].fdno;
       }
   
  +#ifdef       NOISY
   DBGIO(fd, (stderr, "<== Fileno(%p) rc %d %s\n", (fd ? fd : NULL), rc, 
fdbg(fd)));
  +#endif
       return rc;
   }
   
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/rpmio.h
  ============================================================================
  $ cvs diff -u -r1.97.2.9 -r1.97.2.10 rpmio.h
  --- rpm/rpmio/rpmio.h 28 Jun 2016 07:18:12 -0000      1.97.2.9
  +++ rpm/rpmio/rpmio.h 17 Apr 2017 18:19:08 -0000      1.97.2.10
  @@ -39,6 +39,7 @@
   /** \ingroup rpmio
    */
   typedef      struct _FD_s * FD_t;
  +typedef      struct _FDSTAT_s * FDSTAT_t;
   
   /** \ingroup rpmio
    */
  @@ -153,6 +154,7 @@
   /**
    * fileno(3) clone.
    */
  +RPM_GNUC_PURE
   int Fileno(FD_t fd);
   
   /**
  @@ -238,6 +240,69 @@
   int Fallocate(FD_t fd, off_t offset, off_t length);
   
   /**
  + * ftruncate(2) clone.
  + */
  +int Ftruncate(FD_t fd, off_t len);
  +
  +/**
  + * fdatasync(2) clone.
  + */
  +int Fdatasync(FD_t fd);
  +
  +/**
  + * fsync(2) clone.
  + */
  +int Fsync(FD_t fd);
  +
  +/**
  + * mmap(2) clone.
  + */
  +void *Mmap(void *addr, size_t len, int prot, int flags, FD_t fd, off_t 
offset);
  +
  +/**
  + * munmap(2) clone.
  + */
  +int Munmap(void * addr, size_t len);
  +
  +/**
  + * mprotect(2) clone.
  + */
  +int Mprotect(void * addr, size_t len, int prot);
  +
  +/**
  + * madvise(2) clone.
  + */
  +int Madvise(void *addr, size_t len, int advice);
  +
  +/**
  + * mincore(2) clone.
  + */
  +int Mincore(void * addr, size_t len, unsigned char * vec);
  +
  +/**
  + * splice(2) clone.
  + */
  +ssize_t Splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out,
  +                size_t len, unsigned int flags);
  +
  +/**
  + * tee(2) clone.
  + */
  +ssize_t Tee(int fd_in, int fd_out, size_t len, unsigned int flags);
  +
  +/**
  + * vmsplice(2) clone.
  + */
  +ssize_t Vmsplice(int fd, const struct iovec *iov,
  +                unsigned long nr_segs, unsigned int flags);
  +
  +/**
  + * prctl(2) clone.
  + */
  +int Prctl(int option, unsigned long arg2, unsigned long arg3,
  +                   unsigned long arg4, unsigned long arg5);
  +
  +/**
    * chown(2) clone.
    * @todo Implement remotely.
    */
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/rpmio_internal.h
  ============================================================================
  $ cvs diff -u -r2.127.2.7 -r2.127.2.8 rpmio_internal.h
  --- rpm/rpmio/rpmio_internal.h        24 Sep 2014 13:27:53 -0000      
2.127.2.7
  +++ rpm/rpmio/rpmio_internal.h        17 Apr 2017 18:19:08 -0000      
2.127.2.8
  @@ -32,20 +32,41 @@
    * Identify per-desciptor I/O operation statistics.
    */
   typedef enum fdOpX_e {
  -    FDSTAT_READ              = 0,    /*!< Read statistics index. */
  -    FDSTAT_WRITE     = 1,    /*!< Write statistics index. */
  -    FDSTAT_SEEK              = 2,    /*!< Seek statistics index. */
  -    FDSTAT_CLOSE     = 3,    /*!< Close statistics index */
  -    FDSTAT_DIGEST    = 4,    /*!< Digest statistics index. */
  -    FDSTAT_MAX               = 5
  +    FDSTAT_READ              = 0,    /*!< read statistics index. */
  +    FDSTAT_WRITE     = 1,    /*!< write statistics index. */
  +    FDSTAT_SEEK              = 2,    /*!< seek statistics index. */
  +    FDSTAT_CLOSE     = 3,    /*!< close statistics index */
  +    FDSTAT_DIGEST    = 4,    /*!< digest statistics index. */
  +    FDSTAT_FALLOCATE = 5,    /*!< fallocate statistics index. */
  +    FDSTAT_FDATASYNC = 6,    /*!< fdatasync statistics index. */
  +    FDSTAT_FADVISE   = 7,    /*!< fadvise statistics index. */
  +    FDSTAT_FSYNC     = 8,    /*!< fsync statistics index. */
  +    FDSTAT_MAX
   } fdOpX;
   
   /** \ingroup rpmio
  + * Per-descriptor flag bits.
  + */
  +typedef enum fdFlags_e {
  +    RPMFD_FLAG_NONE          = 0,
  +     /* 0 - 24 unused */
  +    RPMFD_FLAG_FALLOCATE     = (1 << 25),
  +    RPMFD_FLAG_FADVISE               = (1 << 26),
  +    RPMFD_FLAG_FDATASYNC     = (1 << 27),
  +    RPMFD_FLAG_FSYNC         = (1 << 28),
  +    RPMFD_FLAG_DEBUGREFS     = (1 << 29),
  +    RPMFD_FLAG_DEBUGIO               = (1 << 30),
  +} fdFlags;
  +#define      RPMFD_SET(_flags, _a)   ((_flags) |= RPMFD_FLAG_##_a)
  +#define      RPMFD_CLR(_flags, _a)   ((_flags) &= ~RPMFD_FLAG_##_a)
  +#define      RPMFD_ISSET(_fd, _a)    ((_fd)->flags &  RPMFD_FLAG_##_a)
  +
  +/** \ingroup rpmio
    * Cumulative statistics for a descriptor.
    */
  -typedef      /*@abstract@*/ struct {
  +struct _FDSTAT_s {
       struct rpmop_s   ops[FDSTAT_MAX];        /*!< Cumulative statistics. */
  -} * FDSTAT_t;
  +};
   
   /** \ingroup rpmio
    */
  @@ -58,16 +79,15 @@
    */
   struct _FD_s {
       struct rpmioItem_s _item;        /*!< usage mutex and pool identifier. */
  -    int              flags;
  -#define      RPMIO_DEBUG_IO          0x40000000
  -#define      RPMIO_DEBUG_REFS        0x20000000
  +    fdFlags  flags;          /* file handle flags */
       int              magic;
   #define      FDMAGIC                 0x04463138
  -    int              nfps;
  -    FDSTACK_t        fps[8];
  +    int              nfps;           /* no. of stacked file handles */
  +    FDSTACK_t        fps[8];         /* stacked file handles */
   
   /*@dependent@*/ /*@relnull@*/
       void *   u;              /* ufdio: URL info */
  +    int              ut;             /* ufdio: URL type */
   /*@relnull@*/
       void *   req;            /* ufdio: HTTP request */
   
  @@ -93,8 +113,8 @@
   
       FDSTAT_t stats;          /* I/O statistics */
   
  -    size_t   ndigests;
  -    DIGEST_CTX *digests;
  +    size_t   ndigests;       /* no. of digests. */
  +    DIGEST_CTX *digests;     /* digest contexts. */
   
   /*null@*/
       const char *contentType; /* ufdio: (HTTP) */
  @@ -112,18 +132,14 @@
   
   #define      FDSANE(fd)      assert(fd != NULL && fd->magic == FDMAGIC)
   
  -#define DBG(_f, _m, _x) \
  +#define DBG(_fd, _flag, _fmt) \
       /*@-modfilesys@*/ \
  -    if ((_rpmio_debug | ((_f) ? ((FD_t)(_f))->flags : 0)) & (_m)) fprintf _x 
\
  +    if (_rpmio_debug || ((_fd) ? RPMFD_ISSET(((FD_t)(_fd)), _flag) : 0)) \
  +     fprintf _fmt \
       /*@=modfilesys@*/
   
  -#if defined(__LCLINT__XXX)
  -#define DBGIO(_f, _x)
  -#define DBGREFS(_f, _x)
  -#else
  -#define DBGIO(_f, _x)   DBG((_f), RPMIO_DEBUG_IO, _x)
  -#define DBGREFS(_f, _x) DBG((_f), RPMIO_DEBUG_REFS, _x)
  -#endif
  +#define DBGIO(_fd, _fmt)   DBG((_fd), DEBUGIO, _fmt)
  +#define DBGREFS(_fd, _fmt) DBG((_fd), DEBUGREFS, _fmt)
   
   #ifdef __cplusplus
   extern "C" {
  @@ -168,7 +184,7 @@
   /** \ingroup rpmio
    */
   /*@unused@*/ static inline
  -void fdSetOpen(FD_t fd, const char * path, int flags, mode_t mode)
  +void fdSetOpen(FD_t fd, const char * opath, int oflags, mode_t omode)
        /*@modifies fd @*/
   {
       FDSANE(fd);
  @@ -176,9 +192,9 @@
        free((void *)fd->opath);
        fd->opath = NULL;
       }
  -    fd->opath = xstrdup(path);
  -    fd->oflags = flags;
  -    fd->omode = mode;
  +    fd->opath = xstrdup(opath);
  +    fd->oflags = oflags;
  +    fd->omode = omode;
   }
   
   /** \ingroup rpmio
  @@ -196,6 +212,17 @@
   
   /** \ingroup rpmio
    */
  +RPM_GNUC_PURE
  +/*@unused@*/ static inline
  +int fdGetFlags(FD_t fd)
  +     /*@*/
  +{
  +    FDSANE(fd);
  +    return fd->flags;
  +}
  +
  +/** \ingroup rpmio
  + */
   /*@unused@*/ static inline
   int fdGetOFlags(FD_t fd)
        /*@*/
  @@ -451,36 +478,64 @@
   
   /** \ingroup rpmio
    */
  -/*@unused@*/ static inline
  -void fdstat_print(/*@null@*/ FD_t fd, const char * msg, FILE * fp)
  -     /*@globals fileSystem @*/
  -     /*@modifies *fp, fileSystem @*/
  +static inline
  +void fdstat_sum(FD_t fd, FDSTAT_t sum)
  +{
  +    if (fd == NULL || fd->stats == NULL || sum == NULL) return;
  +    for (int opx = 0; opx < FDSTAT_MAX; opx++) {
  +     rpmop sop = &fd->stats->ops[opx];
  +     rpmop dop = &sum->ops[opx];
  +     (void) rpmswAdd(dop, sop);
  +    }
  +}
  +
  +/** \ingroup rpmio
  + */
  +static inline
  +void fdstat_print(FD_t fd, const char * msg, FILE * fp)
   {
       static int usec_scale = (1000*1000);
  -    int opx;
   
       if (fd == NULL || fd->stats == NULL) return;
  -    for (opx = 0; opx < 4; opx++) {
  +    for (int opx = 0; opx < FDSTAT_MAX; opx++) {
  +     static const char *const names[] = {
  +         [FDSTAT_READ]       = "  read",
  +         [FDSTAT_WRITE]      = " write",
  +         [FDSTAT_SEEK]       = "  seek",
  +#ifdef       NOISY
  +         [FDSTAT_CLOSE]      = " close",
  +#endif
  +         [FDSTAT_DIGEST]     = "digest",
  +         [FDSTAT_FALLOCATE]  = " alloc",
  +         [FDSTAT_FDATASYNC]  = " dsync",
  +#ifdef       NOISY
  +         [FDSTAT_FADVISE]    = "advise",
  +#endif
  +         [FDSTAT_FSYNC]      = "  sync",
  +     };
        rpmop op = &fd->stats->ops[opx];
  +
  +     if (names[opx] == NULL || *names[opx] == '\0') continue;
        if (op->count <= 0) continue;
  +
        switch (opx) {
        case FDSTAT_READ:
  -         if (msg != NULL) fprintf(fp, "%s:", msg);
  -         fprintf(fp, "%8d reads, %8lu total bytes in %d.%06d secs\n",
  -             op->count, (unsigned long)op->bytes,
  -             (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
  -         /*@switchbreak@*/ break;
        case FDSTAT_WRITE:
  -         if (msg != NULL) fprintf(fp, "%s:", msg);
  -         fprintf(fp, "%8d writes, %8lu total bytes in %d.%06d secs\n",
  -             op->count, (unsigned long)op->bytes,
  -             (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
  -         /*@switchbreak@*/ break;
        case FDSTAT_SEEK:
  -         /*@switchbreak@*/ break;
        case FDSTAT_CLOSE:
  -         /*@switchbreak@*/ break;
  +     case FDSTAT_FALLOCATE:
  +     case FDSTAT_FDATASYNC:
  +     case FDSTAT_FADVISE:
  +     case FDSTAT_FSYNC:
  +     default:
  +         break;
        }
  +
  +     if (msg != NULL) fprintf(fp, "%s:", msg);
  +     fprintf(fp, "%8d %s(s), %8lu total bytes in %d.%06d secs\n",
  +             op->count, names[opx], (unsigned long)op->bytes,
  +             (int)(op->usecs/usec_scale), (int)(op->usecs%usec_scale));
  +
       }
   }
   
  @@ .
  patch -p0 <<'@@ .'
  Index: rpm/rpmio/rpmrpc.c
  ============================================================================
  $ cvs diff -u -r2.99.2.5 -r2.99.2.6 rpmrpc.c
  --- rpm/rpmio/rpmrpc.c        11 May 2015 21:10:19 -0000      2.99.2.5
  +++ rpm/rpmio/rpmrpc.c        17 Apr 2017 18:19:08 -0000      2.99.2.6
  @@ -72,6 +72,7 @@
   /* =============================================================== */
   int Mkdir (const char * path, mode_t mode)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
   
  @@ -96,7 +97,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
       return mkdir(path, mode);
  @@ -104,6 +105,7 @@
   
   int Chdir (const char * path)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
   
  @@ -119,7 +121,7 @@
        return davChdir(path);
   #else
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     return rc;
   #endif
        /*@notreached@*/ break;
       case URL_IS_PATH:
  @@ -132,7 +134,7 @@
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
       return chdir(path);
  @@ -140,6 +142,7 @@
   
   int Rmdir (const char * path)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
   
  @@ -164,7 +167,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
       return rmdir(path);
  @@ -175,9 +178,9 @@
   
   int Chroot(const char * path)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -193,7 +196,7 @@
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
   
  @@ -218,6 +221,7 @@
   
   int Open(const char * path, int flags, mode_t mode)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
       int fdno;
  @@ -236,7 +240,7 @@
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
   
  @@ -257,10 +261,13 @@
       /* XXX if the open(2) fails, try to strip a possible chroot(2) prefix. */
       if (fdno < 0 && errno == ENOENT) {
        const char *dbpath = rpmExpand("%{?_dbpath}/", NULL);
  -     const char * fn = strstr(path + 1, dbpath);
  +     const char * resolved_dbpath = Realpath(dbpath, NULL);
  +     const char * fn = strstr(path + 1, resolved_dbpath);
        if (fn)
            fdno = open(fn, flags, mode);
  +     resolved_dbpath = _free(resolved_dbpath);
        dbpath = _free(dbpath);
  +     
       }
       if (fdno >= 0) {
        if (fcntl(fdno, F_SETFD, FD_CLOEXEC) < 0) {
  @@ -285,6 +292,7 @@
   
   int Rename (const char * oldpath, const char * newpath)
   {
  +    int rc = -2;
       const char *oe = NULL;
       const char *ne = NULL;
       int oldut, newut;
  @@ -310,7 +318,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
   
  @@ -321,7 +329,7 @@
   fprintf(stderr, "*** rename old %*s new %*s\n", (int)(oe - oldpath), 
oldpath, (int)(ne - newpath), newpath);
        if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
            !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
  -         return -2;
  +         return rc;
        return ftpRename(oldpath, newpath);
        /*@notreached@*/ break;
       case URL_IS_HTTPS:               /* XXX WRONG WRONG WRONG */
  @@ -336,7 +344,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
       return rename(oldpath, newpath);
  @@ -344,6 +352,7 @@
   
   int Link (const char * oldpath, const char * newpath)
   {
  +    int rc = -2;
       const char *oe = NULL;
       const char *ne = NULL;
       int oldut, newut;
  @@ -362,7 +371,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
   
  @@ -376,7 +385,7 @@
   fprintf(stderr, "*** link old %*s new %*s\n", (int)(oe - oldpath), oldpath, 
(int)(ne - newpath), newpath);
        if (!(oldut == newut && oe && ne && (oe - oldpath) == (ne - newpath) &&
            !xstrncasecmp(oldpath, newpath, (oe - oldpath))))
  -         return -2;
  +         return rc;
        oldpath = oe;
        newpath = ne;
        break;
  @@ -386,7 +395,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
       return link(oldpath, newpath);
  @@ -394,10 +403,11 @@
   
   /* XXX build/build.c: analogue to unlink(2). */
   
  -int Unlink(const char * path) {
  +int Unlink(const char * path)
  +{
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_FTP:
  @@ -994,6 +1004,7 @@
        /*@modifies *st, *rlbuf, ftpBufAlloced, ftpBuf,
                fileSystem, internalState @*/
   {
  +    int rc = -2;
       FD_t fd;
       const char * path;
       int bufLength, moretodo;
  @@ -1004,12 +1015,11 @@
       char * bn = NULL;
       size_t nbn = 0;
       urlinfo u;
  -    int rc;
   
       n = ne = o = oe = NULL;
       (void) urlPath(url, &path);
       if (*path == '\0')
  -     return -2;
  +     return rc;
   
       switch (ftpSysCall) {
       case DO_FTP_GLOB:
  @@ -1022,7 +1032,7 @@
       default:
        urldn = alloca_strdup(url);
        if ((bn = (char *) strrchr(urldn, '/')) == NULL)
  -         return -2;
  +         return rc;
        else if (bn == path)
            bn = (char *) ".";
        else
  @@ -1362,9 +1372,9 @@
        /*@globals ftpBufAlloced, ftpBuf @*/
        /*@modifies ftpBufAlloced, ftpBuf @*/
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_FTP:
  @@ -1402,9 +1412,9 @@
        /*@globals ftpBufAlloced, ftpBuf @*/
        /*@modifies ftpBufAlloced, ftpBuf @*/
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_FTP:
  @@ -1440,11 +1450,12 @@
   
   int Fstat(FD_t fd, struct stat * st)
   {
  +    int rc = -2;
       const char * path = fdGetOPath(fd);
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
  +    FDSANE(fd);
       if (fd == NULL || path == NULL || *path == '\0' || st == NULL) {
        errno = ENOENT;
        goto exit;
  @@ -1478,6 +1489,8 @@
        st->st_atime = st->st_ctime = st->st_mtime;
        st->st_blksize = 4 * 1024;  /* HACK correct for linux ext */
        st->st_blocks = (st->st_size + 511)/512;
  +     rc = 0;
  +     goto exit;
        break;
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  @@ -1494,19 +1507,19 @@
   
   int Fadvise(FD_t fd, off_t offset, off_t len, int advice)
   {
  +    int rc = -2;
       const char * path = fdGetOPath(fd);
       const char * lpath;
       int ut = urlPath(path, &lpath);
       int fdno = Fileno(fd);
  -    int rc;
   
  -if (_rpmio_debug)
  -fprintf(stderr, "*** %s(%p,0x%x,0x%x,0x%x) fdno %d path %s\n", __FUNCTION__, 
fd, (unsigned)offset, (unsigned)len, advice, fdno, path);
  +    FDSANE(fd);
  +DBGIO(fd, (stderr, "--> %s(%p,0x%x,0x%x,0x%x) fdno %d path %s\n", 
__FUNCTION__, fd, (unsigned)offset, (unsigned)len, advice, fdno, path));
   
       /* XXX errno is not set by fallocate/posix_fallocate */
       if (fd == NULL || fdno < 0) {
  -     rc = EBADF;
  -     return rc;
  +     errno = EBADF;
  +     goto exit;
       }
   
       switch (ut) {
  @@ -1514,8 +1527,8 @@
       case URL_IS_UNKNOWN:
        break;
       default:
  -     rc = ENODEV;    
  -     return rc;
  +     errno = ESPIPE; 
  +     goto exit;
        /*@notreached@*/ break;
       }
   
  @@ -1527,39 +1540,44 @@
       case POSIX_FADV_NOREUSE:
       case POSIX_FADV_WILLNEED:
       case POSIX_FADV_DONTNEED:
  +     fdstat_enter(fd, FDSTAT_FADVISE);
        rc = posix_fadvise(fdno, offset, len, advice);
  +     fdstat_exit(fd, FDSTAT_FADVISE, len);
   #else
  -     rc = ENOSYS;
  +     errno = ENOSYS;
  +     goto exit;
   #endif
        break;
       default:
  -     rc = EINVAL;
  +     errno = EINVAL;
  +     goto exit;
        break;
       }
   
  +exit:
       if (rc != 0)
  -     rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x,0x%x) failed: rc %d\n"),
  +     rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x,0x%x) failed: rc %d %m\n"),
                __FUNCTION__, fdno, (unsigned)offset, (unsigned)len, rc);
   
       return rc;
   }
   
  -#undef       HAVE_FALLOCATE  /* XXX hmmm, fallocate64 is AWOL in F11. */
  +#undef HAVE_FALLOCATE  /* XXX hmmm, fallocate64 is AWOL in F11. */
   int Fallocate(FD_t fd, off_t offset, off_t len)
   {
  +    int rc = -2;
       const char * path = fdGetOPath(fd);
       const char * lpath;
       int ut = urlPath(path, &lpath);
       int fdno = Fileno(fd);
  -    int rc;
   
  -if (_rpmio_debug)
  -fprintf(stderr, "*** %s(%p,0x%x,0x%x) fdno %d path %s\n", __FUNCTION__, fd, 
(unsigned)offset, (unsigned)len, fdno, path);
  +    FDSANE(fd);
  +DBGIO(fd, (stderr, "--> %s(%p,0x%x,0x%x) fdno %d path %s\n", __FUNCTION__, 
fd, (unsigned)offset, (unsigned)len, fdno, path));
   
       /* XXX errno is not set by fallocate/posix_fallocate */
       if (fd == NULL || fdno < 0) {
  -     rc = EBADF;
  -     return rc;
  +     errno = EBADF;
  +     goto exit;
       }
   
       switch (ut) {
  @@ -1567,33 +1585,161 @@
       case URL_IS_UNKNOWN:
        break;
       default:
  -     rc = ENODEV;    
  -     return rc;
  +     errno = ENODEV; 
  +     goto exit;
        /*@notreached@*/ break;
       }
   
  -#if defined(HAVE_FALLOCATE)
  +#if defined(HAVE_POSIX_FALLOCATE)
  +    fdstat_enter(fd, FDSTAT_FALLOCATE);
  +    rc = posix_fallocate(fdno, offset, len);
  +    fdstat_exit(fd, FDSTAT_FALLOCATE, len);
  +#elif defined(HAVE_FALLOCATE)
       /* XXX linux FALLOC_FL_KEEP_SIZE zeroes allocated blocks */
  +    fdstat_enter(fd, FDSTAT_FALLOCATE);
       rc = (int) fallocate(fdno, 0, (loff_t)offset, (loff_t)len);
  -#elif defined(HAVE_POSIX_FALLOCATE)
  -    rc = posix_fallocate(fdno, offset, len);
  +    fdstat_exit(fd, FDSTAT_FALLOCATE, len);
   #else
  -    rc = ENOSYS;
  +    errno = ENOSYS;
   #endif
   
  +exit:
       if (rc != 0)
  -     rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x,0x%x) failed: rc %d\n"),
  +     rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x,0x%x) failed: rc %d %m\n"),
                __FUNCTION__, fdno, (unsigned)offset, (unsigned)len, rc);
   
       return rc;
   }
   
  -#ifdef       NOTYET  /* XXX figger mmap or posix_memalign first */
  -void *Mmap(void *addr, size_t length, int prot, int flags,
  +int Ftruncate(FD_t fd, off_t len)
  +{
  +    int rc = -2;
  +    const char * path = fdGetOPath(fd);
  +    const char * lpath;
  +    int ut = urlPath(path, &lpath);
  +    int fdno = Fileno(fd);
  +
  +    FDSANE(fd);
  +DBGIO(fd, (stderr, "--> %s(%p,0x%x) fdno %d path %s\n", __FUNCTION__, fd, 
(unsigned)len, fdno, path));
  +
  +    if (fd == NULL || fdno < 0) {
  +     errno = EBADF;
  +     goto exit;
  +    }
  +
  +    switch (ut) {
  +    case URL_IS_PATH:
  +    case URL_IS_UNKNOWN:
  +     break;
  +    default:
  +     errno = EINVAL; 
  +     goto exit;
  +     /*@notreached@*/ break;
  +    }
  +
  +#if defined(HAVE_FTRUNCATE)
  +    rc = ftruncate(fdno, len);
  +#else
  +    errno = ENOSYS;
  +#endif
  +
  +exit:
  +    if (rc != 0)
  +     rpmlog(RPMLOG_DEBUG, _("%s(%d,0x%x) failed: rc %d %m\n"),
  +             __FUNCTION__, fdno, (unsigned)len, rc);
  +
  +    return rc;
  +}
  +
  +int Fdatasync(FD_t fd)
  +{
  +    int rc = -2;
  +    const char * path = fdGetOPath(fd);
  +    const char * lpath;
  +    int ut = urlPath(path, &lpath);
  +    int fdno = Fileno(fd);
  +
  +    FDSANE(fd);
  +DBGIO(fd, (stderr, "--> %s(%p) fdno %d path %s\n", __FUNCTION__, fd, fdno, 
path));
  +
  +    if (fd == NULL || fdno < 0) {
  +     errno = EBADF;
  +     goto exit;
  +    }
  +
  +    switch (ut) {
  +    case URL_IS_PATH:
  +    case URL_IS_UNKNOWN:
  +     break;
  +    default:
  +     errno = EINVAL; 
  +     goto exit;
  +     /*@notreached@*/ break;
  +    }
  +
  +#if defined(HAVE_FDATASYNC)
  +    fdstat_enter(fd, FDSTAT_FDATASYNC);
  +    rc = fdatasync(fdno);
  +    fdstat_exit(fd, FDSTAT_FDATASYNC, 0);    /* XXX #bytes? */
  +#else
  +    errno = ENOSYS;
  +#endif
  +
  +exit:
  +    if (rc != 0)
  +     rpmlog(RPMLOG_DEBUG, _("%s(%d) failed: rc %d %m\n"),
  +             __FUNCTION__, fdno, rc);
  +
  +    return rc;
  +}
  +
  +int Fsync(FD_t fd)
  +{
  +    int rc = -2;
  +    const char * path = fdGetOPath(fd);
  +    const char * lpath;
  +    int ut = urlPath(path, &lpath);
  +    int fdno = Fileno(fd);
  +
  +    FDSANE(fd);
  +DBGIO(fd, (stderr, "--> %s(%p) fdno %d path %s\n", __FUNCTION__, fd, fdno, 
path));
  +
  +    if (fd == NULL || fdno < 0) {
  +     errno = EBADF;
  +     goto exit;
  +    }
  +
  +    switch (ut) {
  +    case URL_IS_PATH:
  +    case URL_IS_UNKNOWN:
  +     break;
  +    default:
  +     errno = EINVAL; 
  +     goto exit;
  +     /*@notreached@*/ break;
  +    }
  +
  +#if defined(HAVE_FDATASYNC)
  +    fdstat_enter(fd, FDSTAT_FSYNC);
  +    rc = fdatasync(fdno);
  +    fdstat_exit(fd, FDSTAT_FSYNC, 0);        /* XXX #bytes? */
  +#else
  +    errno = ENOSYS;
  +#endif
  +
  +exit:
  +    if (rc != 0)
  +     rpmlog(RPMLOG_DEBUG, _("%s(%d) failed: rc %d %m\n"),
  +             __FUNCTION__, fdno, rc);
  +
  +    return rc;
  +}
  +
  +void *Mmap(void *addr, size_t len, int prot, int flags,
                     FD_t fd, off_t offset)
   {
       int fdno = (fd ? Fileno(fd) : -1);
  -    void * ret = mmap(addr, length, prot, flags, fdno, offset);
  +    void * ret = mmap(addr, len, prot, flags, fdno, offset);
       if (ret == NULL || ret == (void *)-1)
        rpmlog(RPMLOG_ERR, _("%s(%p[%u],0x%x,0x%x,%p,0x%x) failed: %m\n"),
                __FUNCTION__, addr, (unsigned)len, prot, flags, fd,
  @@ -1603,7 +1749,7 @@
       return ret;
   }
   
  -int Munmap(const void * addr, size_t len)
  +int Munmap(void * addr, size_t len)
   {
       int rc = munmap(addr, len);
       if (rc < 0)
  @@ -1614,19 +1760,17 @@
       return rc;
   }
   
  -int Mprotect(const void * addr, size_t len, int prot)
  +int Mprotect(void * addr, size_t len, int prot)
   {
       int rc = mprotect(addr, len, prot);
       if (rc < 0)
        rpmlog(RPMLOG_ERR, _("%s(%p[%u],%d) failed: %m\n"),
                __FUNCTION__, addr, (unsigned)len, prot);
   if (_rpmio_debug)
  -fprintf(stderr, "<-- %s(%p[%u],%d) rc %d\n", __FUNCTION__, addr, len, prot, 
rc);
  +fprintf(stderr, "<-- %s(%p[%u],%d) rc %d\n", __FUNCTION__, addr, 
(unsigned)len, prot, rc);
       return rc;
   }
  -#endif
   
  -#ifdef       NOTYET  /* XXX figger posix_fadvise or posix_madvise first */
   int Madvise(void *addr, size_t len, int advice)
   {
       int rc = madvise(addr, len, advice);
  @@ -1634,48 +1778,137 @@
        rpmlog(RPMLOG_ERR, _("%s(%p[%u],%d) failed: %m\n"),
                __FUNCTION__, addr, (unsigned)len, advice);
   if (_rpmio_debug)
  -fprintf(stderr, "<-- %s(%p[%u],%d) rc %d\n", __FUNCTION__, addr, len, 
advice, rc);
  +fprintf(stderr, "<-- %s(%p[%u],%d) rc %d\n", __FUNCTION__, addr, 
(unsigned)len, advice, rc);
       return rc;
   }
   
  -int Fadvise(FD_t fd, off_t offset, off_t len, int advice)
  +int Mincore(void * addr, size_t len, unsigned char * vec)
  +{
  +    int rc = mincore(addr, len, vec);
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%p[%u],%p) failed: %m\n"),
  +             __FUNCTION__, addr, (unsigned)len, vec);
  +if (_rpmio_debug)
  +fprintf(stderr, "<-- %s(%p[%u],%p) rc %d\n", __FUNCTION__, addr, 
(unsigned)len, vec, rc);
  +    return rc;
  +}
  +
  +#ifdef       NOTYET
  +#include <sys/sendfile.h>
  +/* XXX kernel < 2.6.33, one of {in,out}_fd must be a socket. */
  +ssize_t Sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
  +{
  +    int rc = sendfile(out_fd, in_fd, offset, count);
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%d, %d, %p, %u) failed: %m\n"),
  +             __FUNCTION__, out_fd, in_fd, offset, (unsigned)count);
  +if (_rpmio_debug)
  +fprintf(stderr, _("<-- %s(%d, %d, %p, %u) rc %d\n"), __FUNCTION__, out_fd, 
in_fd, offset, (unsigned)count, rc);
  +    return rc;
  +}
  +
  +/* XXX if off_{in,out} are NULL, fd_{in_out} offset is changed. */
  +/* XXX if off_{in,out} are not NULL, fd_{in_out} offset are not changed. */
  +static loff_t
  +copy_file_range(int fd_in, loff_t *off_in, int fd_out,
  +             loff_t *off_out, size_t len, unsigned int flags)
  +{
  +    return syscall(__NR_copy_file_range, fd_in, off_in, fd_out,
  +                                     off_out, len, flags);
  +}
  +
  +ssize_t Copy_file_range(int fd_in, loff_t *off_in, int fd_out, loff_t 
*off_out,
  +             size_t len, unsigned int flags)
  +{
  +    int rc = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%d,%p, %d,%p, %u, %u) failed: %m\n"),
  +             __FUNCTION__, fd_in, off_in, fd_out, off_out, (unsigned)len, 
flags);
  +if (_rpmio_debug)
  +fprintf(stderr, _("<-- %s(%d,%p, %d,%p, %u, %u) rc %d\n"),
  +             __FUNCTION__, fd_in, off_in, fd_out, off_out, (unsigned)len, 
flags, rc);
  +    return rc;
  +}
  +#endif       /* NOTYET */
  +
  +/* XXX same note as copy_file_range. one of fd_{in,out} must be a pipe. */
  +ssize_t Splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out,
  +             size_t len, unsigned int flags)
   {
  -    const char * path = fdGetOPath(fd);
  -    const char * lpath;
  -    int ut = urlPath(path, &lpath);
  -    int fdno = Fileno(fd);
       int rc = -2;
  +#ifdef       HAVE_SPLICE
  +    rc = splice(fd_in, off_in, fd_out, off_out, len, flags);
  +#else
  +    errno = ENOSYS;
  +#endif
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%d,%p, %d,%p, %u, %u) failed: %m\n"),
  +             __FUNCTION__, fd_in, off_in, fd_out, off_out, (unsigned)len, 
flags);
  +if (_rpmio_debug)
  +fprintf(stderr, _("<-- %s(%d,%p, %d,%p, %u, %u) rc %d\n"), __FUNCTION__, 
fd_in, off_in, fd_out, off_out, (unsigned)len, flags, rc);
  +    return rc;
  +}
   
  -    if (fd == NULL || fdno < 0) {
  -     errno = EBADF;
  -     goto exit;
  -    }
  +/* XXX both fd_{in,out} must be pipes. */
  +ssize_t Tee(int fd_in, int fd_out, size_t len, unsigned int flags)
  +{
  +    int rc = -2;
  +#ifdef       HAVE_TEE
  +    rc = tee(fd_in, fd_out, len, flags);
  +#else
  +    errno = ENOSYS;
  +#endif
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%d, %d, %u, %u) failed: %m\n"),
  +             __FUNCTION__, fd_in, fd_out, (unsigned)len, flags);
  +if (_rpmio_debug)
  +fprintf(stderr, _("<-- %s(%d, %d, %u, %u) rc %d\n"), __FUNCTION__, fd_in, 
fd_out, (unsigned)len, flags, rc);
  +    return rc;
  +}
   
  -    switch (ut) {
  -    case URL_IS_PATH:
  -    case URL_IS_UNKNOWN:
  -     break;
  -    default:
  -     errno = EINVAL; 
  -     goto exit;
  -     /*@notreached@*/ break;
  -    }
  -    rc = posix_fadvise(fdno, offset, len, advice);
  -    if (rc != 0)
  -     rpmlog(RPMLOG_ERR, _("%s(%d,%d,0x%x,0x%x) failed: %m\n"),
  -             __FUNCTION__, fdno, (unsigned)offset, (unsigned)len, advice);
  -exit:
  +/* XXX fd must be a pipe. */
  +ssize_t Vmsplice(int fd, const struct iovec *iov,
  +             unsigned long nr_segs, unsigned int flags)
  +{
  +    int rc = -2;
  +#ifdef       HAVE_VMSPLICE
  +    rc = vmsplice(fd, iov, nr_segs, flags);
  +#else
  +    errno = ENOSYS;
  +#endif
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%d, %p, %u, %u) failed: %m\n"),
  +             __FUNCTION__, fd, iov, (unsigned)nr_segs, flags);
   if (_rpmio_debug)
  -fprintf(stderr, "<-- %s(%p,0x%x,0x%x,%d) fdno %d path %s rc %d\n", 
__FUNCTION__, fd, (unsigned)offset, (unsigned)len, advice, fdno, path, rc);
  +fprintf(stderr, _("<-- %s(%d, %p, %u, %u) rc %d\n"), __FUNCTION__, fd, iov, 
(unsigned)nr_segs, flags, rc);
       return rc;
   }
  +
  +#ifdef       HAVE_PRCTL
  +#include <sys/prctl.h>
   #endif
  +int Prctl(int option, unsigned long arg2, unsigned long arg3,
  +                 unsigned long arg4, unsigned long arg5)
  +{
  +    int rc = -2;
  +#ifdef       HAVE_PRCTL
  +    rc = prctl(option, arg2, arg3, arg4, arg5);
  +#else
  +    errno = ENOSYS;
  +#endif
  +    if (rc < 0)
  +     rpmlog(RPMLOG_ERR, _("%s(%d,%lu,%lu,%lu,%lu) failed: %m\n"),
  +             __FUNCTION__, option, arg2, arg3, arg4, arg5);
  +if (_rpmio_debug)
  +fprintf(stderr, _("<-- %s(%d,%lu,%lu,%lu,%lu) rc %d\n"), __FUNCTION__, 
option, arg2, arg3, arg4, arg5, rc);
  +    return rc;
  +}
   
   int Chown(const char * path, uid_t owner, gid_t group)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -1703,10 +1936,10 @@
   
   int Fchown(FD_t fd, uid_t owner, gid_t group)
   {
  +    int rc = -2;
       const char * path = fdGetOPath(fd);
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -1734,9 +1967,9 @@
   
   int Lchown(const char * path, uid_t owner, gid_t group)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -1758,15 +1991,15 @@
       rc = lchown(path, owner, group);
   exit:
   if (_rpmio_debug)
  -fprintf(stderr, "*** %s(%s,%u,%u)\n", __FUNCTION__, path, (unsigned)owner, 
(unsigned)group);
  +fprintf(stderr, "<-- %s(%s,%u,%u)\n", __FUNCTION__, path, (unsigned)owner, 
(unsigned)group);
       return rc;
   }
   
   int Chmod(const char * path, mode_t mode)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -1794,10 +2027,10 @@
   
   int Lchmod(const char * path, mode_t mode)
   {
  +    int rc = -2;
   #if defined(HAVE_LCHMOD)
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -1820,19 +2053,18 @@
   exit:
   if (_rpmio_debug)
   fprintf(stderr, "<-- %s(%s,%0o) rc %d\n", __FUNCTION__, path, (int)mode, rc);
  -    return rc;
   #else
       errno = ENOSYS;
  -    return -2;
   #endif
  +    return rc;
   }
   
   int Fchmod(FD_t fd, mode_t mode)
   {
  +    int rc = -2;
       const char * path = fdGetOPath(fd);
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -1854,18 +2086,19 @@
       rc = fchmod(Fileno(fd), mode);
   exit:
   if (_rpmio_debug)
  -fprintf(stderr, "*** %s(%p,%0o) path %s rc %d\n", __FUNCTION__, fd, 
(int)mode, path, rc);
  +fprintf(stderr, "<-- %s(%p,%0o) path %s rc %d\n", __FUNCTION__, fd, 
(int)mode, path, rc);
       return rc;
   }
   
   int Chflags(const char * path, unsigned int flags)
   {
  +    int rc = -2;
   #if defined(HAVE_CHFLAGS)
       const char * lpath;
       int ut = urlPath(path, &lpath);
   
   if (_rpmio_debug)
  -fprintf(stderr, "*** Chflags(%s,0x%x)\n", path, flags);
  +fprintf(stderr, "--> Chflags(%s,0x%x)\n", path, flags);
       switch (ut) {
       case URL_IS_PATH:
        path = lpath;
  @@ -1880,25 +2113,26 @@
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     goto exit;
        /*@notreached@*/ break;
       }
  -    return chflags(path, flags);
  +    rc = chflags(path, flags);
  +exit:
   #else
       errno = ENOSYS;
  -    return -2;
   #endif
  +    return rc;
   }
   
   int Lchflags(const char * path, unsigned int flags)
   {
  +    int rc = -2;
  +#if defined(HAVE_LCHFLAGS)
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
  -#if defined(HAVE_LCHFLAGS)
   if (_rpmio_debug)
  -fprintf(stderr, "*** Lchflags(%s,0x%x)\n", path, flags);
  +fprintf(stderr, "--> Lchflags(%s,0x%x)\n", path, flags);
       switch (ut) {
       case URL_IS_PATH:
        path = lpath;
  @@ -1913,12 +2147,12 @@
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     goto exit;
        /*@notreached@*/ break;
       }
  -    return lchflags(path, flags);
  +    rc = lchflags(path, flags);
  +exit:
   #else
  -    (void)ut;        /* keep gcc/clang happy */
       errno = ENOSYS;
   #endif
       return rc;
  @@ -1926,6 +2160,7 @@
   
   int Fchflags(FD_t fd, unsigned int flags)
   {
  +    int rc = -2;
   #if defined(HAVE_FCHFLAGS)
       const char * path = fdGetOPath(fd);
       const char * lpath;
  @@ -1947,14 +2182,15 @@
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
        errno = EINVAL;         /* XXX W2DO? */
  -     return -2;
  +     goto exit;
        /*@notreached@*/ break;
       }
  -    return fchflags(Fileno(fd), flags);
  +    rc = fchflags(Fileno(fd), flags);
  +exit:
   #else
       errno = ENOSYS;
  -    return -2;
   #endif
  +    return rc;
   }
   int Mkfifo(const char * path, mode_t mode)
   {
  @@ -1988,9 +2224,9 @@
   
   int Mknod(const char * path, mode_t mode, dev_t dev)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -2020,9 +2256,9 @@
   
   int Utime(const char * path, const struct utimbuf *buf)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -2051,9 +2287,9 @@
   /*@-fixedformalarray@*/
   int Utimes(const char * path, const struct timeval times[2])
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -2083,10 +2319,10 @@
   /*@-fixedformalarray@*/
   int Lutimes(const char * path, const struct timeval times[2])
   {
  +    int rc = -2;
   #ifdef HAVE_LUTIMES
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -2109,21 +2345,20 @@
   exit:
   if (_rpmio_debug)
   fprintf(stderr, "<-- %s(%s,%p) rc %d\n", __FUNCTION__, path, times, rc);
  -    return rc;
   #else
       errno = ENOSYS;
  -    return -2;
   #endif
  +    return rc;
   }
   /*@=fixedformalarray@*/
   
   int Symlink(const char * oldpath, const char * newpath)
   {
  +    int rc = -2;
       const char * opath;
       int out = urlPath(oldpath, &opath);
       const char * npath;
       int nut = urlPath(newpath, &npath);
  -    int rc = -2;
   
       (void)nut;       /* XXX keep gcc/clang quiet. */
       switch (out) {
  @@ -2155,9 +2390,9 @@
        /*@globals ftpBufAlloced, ftpBuf @*/
        /*@modifies ftpBufAlloced, ftpBuf @*/
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_FTP:
  @@ -2195,9 +2430,9 @@
   
   int Access(const char * path, int amode)
   {
  +    int rc = -2;
       const char * lpath;
       int ut = urlPath(path, &lpath);
  -    int rc = -2;
   
       switch (ut) {
       case URL_IS_PATH:
  @@ -2277,6 +2512,7 @@
   int Glob(const char *pattern, int flags,
        int errfunc(const char * epath, int eerrno), void *_pglob)
   {
  +    int rc = GLOB_ABORTED;
       glob_t *pglob = (glob_t *) _pglob;
       const char * lpath;
       int ut = urlPath(pattern, &lpath);
  @@ -2313,7 +2549,7 @@
       case URL_IS_HKP:
       case URL_IS_MONGO:       /* XXX FIXME */
       default:
  -     return -2;
  +     return rc;
        /*@notreached@*/ break;
       }
       return glob(pattern, flags, errfunc, pglob);
  @@ .
______________________________________________________________________
RPM Package Manager                                    http://rpm5.org
CVS Sources Repository                                rpm-cvs@rpm5.org

Reply via email to