- add payload uncompressed size to signature to avoid rewriting header.
authorjbj <devnull@localhost>
Sun, 3 Mar 2002 23:09:49 +0000 (23:09 +0000)
committerjbj <devnull@localhost>
Sun, 3 Mar 2002 23:09:49 +0000 (23:09 +0000)
- drill header sha1 into signature parallel to header+payload md5.
- mandatory "most effective" signature check on query/verify/install.
- don't bother adding empty filemd's to index.
- add Pubkey index, using signer id as binary key.
- display pubkeys in hex when debugging db access.
- retrieve pubkey(s) from rpmdb, not from detached signature file.
- reapply Berkeley DB patch #4491.

CVS patchset: 5341
CVS date: 2002/03/03 23:09:49

15 files changed:
CHANGES
build/pack.c
db/hash/hash_dup.c
db/hash/hash_page.c
lib/package.c
lib/query.c
lib/rpmchecksig.c
lib/rpmlib.h
lib/signature.c
lib/verify.c
rpm.spec
rpm.spec.in
rpmdb/rpmdb.c
rpmdb/rpmdb.h
rpmio/rpmio_internal.h

diff --git a/CHANGES b/CHANGES
index 88472ad..b7a5087 100644 (file)
--- a/CHANGES
+++ b/CHANGES
        - splint fiddles.
        - make peace with gcc-3.1, remove compiler cruft.
        - make peace with automake et al in 8.0, ugh.
+       - add payload uncompressed size to signature to avoid rewriting header.
+       - drill header sha1 into signature parallel to header+payload md5.
+       - mandatory "most effective" signature check on query/verify/install.
+       - don't bother adding empty filemd's to index.
+       - add Pubkey index, using signer id as binary key.
+       - display pubkeys in hex when debugging db access.
+       - retrieve pubkey(s) from rpmdb, not from detached signature file.
 
 4.0.3 -> 4.0.4:
        - solaris: translate i86pc to i386 (#57182).
        - query/verify by install transaction id.
        - rpm-4.0.4 release candidate.
        - add cpanflute2, another perl.req fiddle.
+       - reapply Berkeley DB patch #4491.
 
 4.0.2 -> 4.0.3:
        - update per-interpreter dependency scripts, add sql/tcl (#20295).
index 1f0e982..33b81e9 100644 (file)
@@ -410,12 +410,14 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
     h = headerLink(*hdrp, "writeRPM xfer");
     *hdrp = headerFree(*hdrp, "writeRPM xfer");
 
+#ifdef DYING
     if (Fileno(csa->cpioFdIn) < 0) {
        csa->cpioArchiveSize = 0;
        /* Add a bogus archive size to the Header */
        (void) headerAddEntry(h, RPMTAG_ARCHIVESIZE, RPM_INT32_TYPE,
                &csa->cpioArchiveSize, 1);
     }
+#endif
 
     /* Binary packages now have explicit Provides: name = version-release. */
     if (type == RPMLEAD_BINARY)
@@ -480,10 +482,12 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
        goto exit;
     }
 
+    fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
     if (headerWrite(fd, h, HEADER_MAGIC_YES)) {
        rc = RPMERR_NOSPACE;
        rpmError(RPMERR_NOSPACE, _("Unable to write temp header\n"));
     } else { /* Write the archive and get the size */
+       fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&sha1, NULL, 1);
        if (csa->cpioList != NULL) {
            rc = cpio_doio(fd, h, csa, rpmio_flags);
        } else if (Fileno(csa->cpioFdIn) >= 0) {
@@ -498,6 +502,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
     if (rc)
        goto exit;
 
+#ifdef DYING
     /*
      * Set the actual archive size, and rewrite the header.
      * This used to be done using headerModifyEntry(), but now that headers
@@ -529,6 +534,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
     }
     (void) Fflush(fd);
     fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&sha1, NULL, 1);
+#endif
 
     (void) Fclose(fd);
     fd = NULL;
@@ -542,16 +548,22 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
     sig = rpmNewSignature();
     (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, passPhrase);
     (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, passPhrase);
+
     if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
        rpmMessage(RPMMESS_NORMAL, _("Generating signature: %d\n"), sigtype);
        (void) rpmAddSignature(sig, sigtarget, sigtype, passPhrase);
     }
     
     if (sha1) {
-       (void) headerAddEntry(sig, RPMTAG_SHA1HEADER, RPM_STRING_TYPE, sha1, 1);
+       (void) headerAddEntry(sig, RPMSIGTAG_SHA1, RPM_STRING_TYPE, sha1, 1);
        sha1 = _free(sha1);
     }
 
+    {  int_32 payloadSize = csa->cpioArchiveSize;
+       (void) headerAddEntry(sig, RPMSIGTAG_PAYLOADSIZE, RPM_INT32_TYPE,
+                       &payloadSize, 1);
+    }
+
     /* Reallocate the signature into one contiguous region. */
     sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
     if (sig == NULL) { /* XXX can't happen */
@@ -621,6 +633,7 @@ int writeRPM(Header *hdrp, const char *fileName, int type,
     }
 
     /* Add signatures to header, and write header into the package. */
+    /* XXX header+payload digests/signatures might be checked again here. */
     {  Header nh = headerRead(ifd, HEADER_MAGIC_YES);
 
        if (nh == NULL) {
index f5fbf4f..ad06c52 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Copyright (c) 1996-2001
  *     Sleepycat Software.  All rights reserved.
  */
 /*
@@ -38,7 +38,7 @@
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "$Id: hash_dup.c,v 11.49 2000/12/21 21:54:35 margo Exp $";
+static const char revid[] = "Id: hash_dup.c,v 11.65 2001/08/13 19:11:37 bostic Exp ";
 #endif /* not lint */
 
 /*
@@ -66,8 +66,11 @@ static const char revid[] = "$Id: hash_dup.c,v 11.49 2000/12/21 21:54:35 margo E
 #include "btree.h"
 #include "txn.h"
 
+static int __ham_c_chgpg __P((DBC *,
+    db_pgno_t, u_int32_t, db_pgno_t, u_int32_t));
 static int __ham_check_move __P((DBC *, u_int32_t));
 static int __ham_dcursor __P((DBC *, db_pgno_t, u_int32_t));
+static int __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
 
 /*
  * Called from hash_access to add a duplicate key. nval is the new
@@ -92,13 +95,15 @@ __ham_add_dup(dbc, nval, flags, pgnop)
        db_pgno_t *pgnop;
 {
        DB *dbp;
-       HASH_CURSOR *hcp;
        DBT pval, tmp_val;
+       DB_MPOOLFILE *mpf;
+       HASH_CURSOR *hcp;
        u_int32_t add_bytes, new_size;
        int cmp, ret;
        u_int8_t *hk;
 
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
 
        DB_ASSERT(flags != DB_CURRENT);
@@ -148,8 +153,8 @@ __ham_add_dup(dbc, nval, flags, pgnop)
                        pval.size = LEN_HDATA(hcp->page, dbp->pgsize,
                            hcp->indx);
                        if ((ret = __ham_make_dup(dbp->dbenv,
-                           &pval, &tmp_val, &dbc->rdata.data,
-                           &dbc->rdata.ulen)) != 0 || (ret =
+                           &pval, &tmp_val, &dbc->my_rdata.data,
+                           &dbc->my_rdata.ulen)) != 0 || (ret =
                            __ham_replpair(dbc, &tmp_val, 1)) != 0)
                                return (ret);
                        hk = H_PAIRDATA(hcp->page, hcp->indx);
@@ -167,7 +172,7 @@ __ham_add_dup(dbc, nval, flags, pgnop)
 
                /* Now make the new entry a duplicate. */
                if ((ret = __ham_make_dup(dbp->dbenv, nval,
-                   &tmp_val, &dbc->rdata.data, &dbc->rdata.ulen)) != 0)
+                   &tmp_val, &dbc->my_rdata.data, &dbc->my_rdata.ulen)) != 0)
                        return (ret);
 
                tmp_val.dlen = 0;
@@ -176,7 +181,8 @@ __ham_add_dup(dbc, nval, flags, pgnop)
                case DB_KEYLAST:
                case DB_NODUPDATA:
                        if (dbp->dup_compare != NULL) {
-                               __ham_dsearch(dbc, nval, &tmp_val.doff, &cmp);
+                               __ham_dsearch(dbc,
+                                   nval, &tmp_val.doff, &cmp, flags);
 
                                /* dup dups are not supported w/ sorted dups */
                                if (cmp == 0)
@@ -203,8 +209,7 @@ __ham_add_dup(dbc, nval, flags, pgnop)
                /* Add the duplicate. */
                ret = __ham_replpair(dbc, &tmp_val, 0);
                if (ret == 0)
-                       ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY);
-
+                       ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY);
                if (ret != 0)
                        return (ret);
 
@@ -245,19 +250,21 @@ int
 __ham_dup_convert(dbc)
        DBC *dbc;
 {
+       BOVERFLOW bo;
        DB *dbp;
        DBC **hcs;
+       DBT dbt;
        DB_LSN lsn;
-       PAGE *dp;
+       DB_MPOOLFILE *mpf;
        HASH_CURSOR *hcp;
-       BOVERFLOW bo;
-       DBT dbt;
        HOFFPAGE ho;
+       PAGE *dp;
        db_indx_t i, len, off;
        int c, ret, t_ret;
        u_int8_t *p, *pend;
 
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
 
        /*
@@ -274,7 +281,7 @@ __ham_dup_convert(dbc)
         */
        if ((ret = __ham_get_clist(dbp,
            PGNO(hcp->page), (u_int32_t)hcp->indx, &hcs)) != 0)
-               return (ret);
+               goto err;
 
        /*
         * Now put the duplicates onto the new page.
@@ -301,12 +308,11 @@ __ham_dup_convert(dbc)
                dbt.data = &bo;
 
                ret = __db_pitem(dbc, dp, 0, dbt.size, &dbt, NULL);
-
 finish:                if (ret == 0) {
-                       memp_fset(dbp->mpf, dp, DB_MPOOL_DIRTY);
-                       /*
-                        * Update any other cursors
-                        */
+                       if ((ret = mpf->set(mpf, dp, DB_MPOOL_DIRTY)) != 0)
+                               break;
+
+                       /* Update any other cursors. */
                        if (hcs != NULL && DB_LOGGING(dbc)
                             && IS_SUBTRANSACTION(dbc->txn)) {
                                if ((ret = __ham_chgpg_log(dbp->dbenv,
@@ -319,10 +325,8 @@ finish:            if (ret == 0) {
                                if ((ret = __ham_dcursor(hcs[c],
                                    PGNO(dp), 0)) != 0)
                                        break;
-
                }
                break;
-
        case H_DUPLICATE:
                p = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx));
                pend = p +
@@ -344,39 +348,49 @@ finish:           if (ret == 0) {
                        if ((ret = __db_pitem(dbc, dp,
                            i, BKEYDATA_SIZE(dbt.size), NULL, &dbt)) != 0)
                                break;
-                       /*
-                        * Update any other cursors
-                        */
+
+                       /* Update any other cursors */
+                       if (hcs != NULL && DB_LOGGING(dbc)
+                            && IS_SUBTRANSACTION(dbc->txn)) {
+                               if ((ret = __ham_chgpg_log(dbp->dbenv,
+                                   dbc->txn, &lsn, 0, dbp->log_fileid,
+                                   DB_HAM_DUP, PGNO(hcp->page),
+                                   PGNO(dp), hcp->indx, i)) != 0)
+                                       break;
+                       }
                        for (c = 0; hcs != NULL && hcs[c] != NULL; c++)
                                if (((HASH_CURSOR *)(hcs[c]->internal))->dup_off
                                    == off && (ret = __ham_dcursor(hcs[c],
                                    PGNO(dp), i)) != 0)
-                                       goto out;
+                                       goto err;
                        off += len + 2 * sizeof(db_indx_t);
                }
-out:           break;
-
+               break;
        default:
-               ret = __db_pgfmt(dbp, (u_long)hcp->pgno);
+               ret = __db_pgfmt(dbp->dbenv, (u_long)hcp->pgno);
                break;
        }
-       if (ret == 0) {
-               /*
-                * Now attach this to the source page in place of
-                * the old duplicate item.
-                */
-               __ham_move_offpage(dbc, hcp->page,
+
+       /*
+        * Now attach this to the source page in place of the old duplicate
+        * item.
+        */
+       if (ret == 0)
+               ret = __ham_move_offpage(dbc, hcp->page,
                    (u_int32_t)H_DATAINDEX(hcp->indx), PGNO(dp));
 
-               ret = memp_fset(dbp->mpf, hcp->page, DB_MPOOL_DIRTY);
-               if ((t_ret = memp_fput(dbp->mpf, dp, DB_MPOOL_DIRTY)) != 0)
-                       ret = t_ret;
+err:   if (ret == 0)
+               ret = mpf->set(mpf, hcp->page, DB_MPOOL_DIRTY);
+
+       if ((t_ret =
+           mpf->put(mpf, dp, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0)
+               ret = t_ret;
+
+       if (ret == 0)
                hcp->dup_tlen = hcp->dup_off = hcp->dup_len = 0;
-       } else
-               (void)__db_free(dbc, dp);
 
        if (hcs != NULL)
-               __os_free(hcs, 0);
+               __os_free(dbp->dbenv, hcs, 0);
 
        return (ret);
 }
@@ -444,9 +458,10 @@ __ham_check_move(dbc, add_len)
        u_int32_t add_len;
 {
        DB *dbp;
-       HASH_CURSOR *hcp;
        DBT k, d;
        DB_LSN new_lsn;
+       DB_MPOOLFILE *mpf;
+       HASH_CURSOR *hcp;
        PAGE *next_pagep;
        db_pgno_t next_pgno;
        u_int32_t new_datalen, old_len, rectype;
@@ -454,6 +469,7 @@ __ham_check_move(dbc, add_len)
        int ret;
 
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
 
        hk = H_PAIRDATA(hcp->page, hcp->indx);
@@ -500,10 +516,10 @@ __ham_check_move(dbc, add_len)
        for (next_pgno = NEXT_PGNO(hcp->page); next_pgno != PGNO_INVALID;
            next_pgno = NEXT_PGNO(next_pagep)) {
                if (next_pagep != NULL &&
-                   (ret = memp_fput(dbp->mpf, next_pagep, 0)) != 0)
+                   (ret = mpf->put(mpf, next_pagep, 0)) != 0)
                        return (ret);
 
-               if ((ret = memp_fget(dbp->mpf,
+               if ((ret = mpf->get(mpf,
                    &next_pgno, DB_MPOOL_CREATE, &next_pagep)) != 0)
                        return (ret);
 
@@ -519,7 +535,7 @@ __ham_check_move(dbc, add_len)
        /* Add new page at the end of the chain. */
        if (P_FREESPACE(next_pagep) < new_datalen && (ret =
            __ham_add_ovflpage(dbc, next_pagep, 1, &next_pagep)) != 0) {
-               (void)memp_fput(dbp->mpf, next_pagep, 0);
+               (void)mpf->put(mpf, next_pagep, 0);
                return (ret);
        }
 
@@ -557,13 +573,14 @@ __ham_check_move(dbc, add_len)
                    dbp->log_fileid, PGNO(next_pagep),
                    (u_int32_t)NUM_ENT(next_pagep), &LSN(next_pagep),
                    &k, &d)) != 0) {
-                       (void)memp_fput(dbp->mpf, next_pagep, 0);
+                       (void)mpf->put(mpf, next_pagep, 0);
                        return (ret);
                }
+       } else
+               LSN_NOT_LOGGED(new_lsn);
 
-               /* Move lsn onto page. */
-               LSN(next_pagep) = new_lsn;      /* Structure assignment. */
-       }
+       /* Move lsn onto page. */
+       LSN(next_pagep) = new_lsn;      /* Structure assignment. */
 
        __ham_copy_item(dbp->pgsize,
            hcp->page, H_KEYINDEX(hcp->indx), next_pagep);
@@ -581,7 +598,7 @@ __ham_check_move(dbc, add_len)
         * Note that __ham_del_pair should dirty the page we're moving
         * the items from, so we need only dirty the new page ourselves.
         */
-       if ((ret = memp_fset(dbp->mpf, next_pagep, DB_MPOOL_DIRTY)) != 0)
+       if ((ret = mpf->set(mpf, next_pagep, DB_MPOOL_DIRTY)) != 0)
                goto out;
 
        /* Update all cursors that used to point to this item. */
@@ -596,12 +613,17 @@ __ham_check_move(dbc, add_len)
         * __ham_del_pair decremented nelem.  This is incorrect;  we
         * manually copied the element elsewhere, so the total number
         * of elements hasn't changed.  Increment it again.
+        *
+        * !!!
+        * Note that we still have the metadata page pinned, and
+        * __ham_del_pair dirtied it, so we don't need to set the dirty
+        * flag again.
         */
        if (!STD_LOCKING(dbc))
                hcp->hdr->nelem++;
 
 out:
-       (void)memp_fput(dbp->mpf, hcp->page, DB_MPOOL_DIRTY);
+       (void)mpf->put(mpf, hcp->page, DB_MPOOL_DIRTY);
        hcp->page = next_pagep;
        hcp->pgno = PGNO(hcp->page);
        hcp->indx = NUM_ENT(hcp->page) - 2;
@@ -620,9 +642,8 @@ out:
  * This is really just a special case of __onpage_replace; we should
  * probably combine them.
  *
- * PUBLIC: void __ham_move_offpage __P((DBC *, PAGE *, u_int32_t, db_pgno_t));
  */
-void
+static int
 __ham_move_offpage(dbc, pagep, ndx, pgno)
        DBC *dbc;
        PAGE *pagep;
@@ -630,32 +651,34 @@ __ham_move_offpage(dbc, pagep, ndx, pgno)
        db_pgno_t pgno;
 {
        DB *dbp;
-       HASH_CURSOR *hcp;
        DBT new_dbt;
        DBT old_dbt;
        HOFFDUP od;
        db_indx_t i;
        int32_t shrink;
        u_int8_t *src;
+       int ret;
 
        dbp = dbc->dbp;
-       hcp = (HASH_CURSOR *)dbc->internal;
        od.type = H_OFFDUP;
        UMRW_SET(od.unused[0]);
        UMRW_SET(od.unused[1]);
        UMRW_SET(od.unused[2]);
        od.pgno = pgno;
+       ret = 0;
 
        if (DB_LOGGING(dbc)) {
                new_dbt.data = &od;
                new_dbt.size = HOFFDUP_SIZE;
                old_dbt.data = P_ENTRY(pagep, ndx);
                old_dbt.size = LEN_HITEM(pagep, dbp->pgsize, ndx);
-               (void)__ham_replace_log(dbp->dbenv,
+               if ((ret = __ham_replace_log(dbp->dbenv,
                    dbc->txn, &LSN(pagep), 0, dbp->log_fileid,
                    PGNO(pagep), (u_int32_t)ndx, &LSN(pagep), -1,
-                   &old_dbt, &new_dbt, 0);
-       }
+                   &old_dbt, &new_dbt, 0)) != 0)
+                       return (ret);
+       } else
+               LSN_NOT_LOGGED(LSN(pagep));
 
        shrink = LEN_HITEM(pagep, dbp->pgsize, ndx) - HOFFDUP_SIZE;
 
@@ -672,6 +695,7 @@ __ham_move_offpage(dbc, pagep, ndx, pgno)
 
        /* Now copy the offdup entry onto the page. */
        memcpy(P_ENTRY(pagep, ndx), &od, HOFFDUP_SIZE);
+       return (ret);
 }
 
 /*
@@ -679,13 +703,14 @@ __ham_move_offpage(dbc, pagep, ndx, pgno)
  *     Locate a particular duplicate in a duplicate set.  Make sure that
  *     we exit with the cursor set appropriately.
  *
- * PUBLIC: void __ham_dsearch __P((DBC *, DBT *, u_int32_t *, int *));
+ * PUBLIC: void __ham_dsearch
+ * PUBLIC:     __P((DBC *, DBT *, u_int32_t *, int *, u_int32_t));
  */
 void
-__ham_dsearch(dbc, dbt, offp, cmpp)
+__ham_dsearch(dbc, dbt, offp, cmpp, flags)
        DBC *dbc;
        DBT *dbt;
-       u_int32_t *offp;
+       u_int32_t *offp, flags;
        int *cmpp;
 {
        DB *dbp;
@@ -697,10 +722,7 @@ __ham_dsearch(dbc, dbt, offp, cmpp)
 
        dbp = dbc->dbp;
        hcp = (HASH_CURSOR *)dbc->internal;
-       if (dbp->dup_compare == NULL)
-               func = __bam_defcmp;
-       else
-               func = dbp->dup_compare;
+       func = dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare;
 
        i = F_ISSET(hcp, H_CONTINUE) ? hcp->dup_off: 0;
        data = HKEYDATA_DATA(H_PAIRDATA(hcp->page, hcp->indx)) + i;
@@ -710,12 +732,26 @@ __ham_dsearch(dbc, dbt, offp, cmpp)
                data += sizeof(db_indx_t);
                cur.data = data;
                cur.size = (u_int32_t)len;
+
+               /*
+                * If we find an exact match, we're done.  If in a sorted
+                * duplicate set and the item is larger than our test item,
+                * we're done.  In the latter case, if permitting partial
+                * matches, it's not a failure.
+                */
                *cmpp = func(dbp, dbt, &cur);
-               if (*cmpp == 0 || (*cmpp < 0 && dbp->dup_compare != NULL))
+               if (*cmpp == 0)
                        break;
+               if (*cmpp < 0 && dbp->dup_compare != NULL) {
+                       if (flags == DB_GET_BOTH_RANGE)
+                               *cmpp = 0;
+                       break;
+               }
+
                i += len + 2 * sizeof(db_indx_t);
                data += len + sizeof(db_indx_t);
        }
+
        *offp = i;
        hcp->dup_off = i;
        hcp->dup_len = len;
@@ -727,29 +763,22 @@ __ham_dsearch(dbc, dbt, offp, cmpp)
  * __ham_cprint --
  *     Display the current cursor list.
  *
- * PUBLIC: int __ham_cprint __P((DB *));
+ * PUBLIC: void __ham_cprint __P((DBC *));
  */
-int
-__ham_cprint(dbp)
-       DB *dbp;
+void
+__ham_cprint(dbc)
+       DBC *dbc;
 {
        HASH_CURSOR *cp;
-       DBC *dbc;
 
-       MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp);
-       for (dbc = TAILQ_FIRST(&dbp->active_queue);
-           dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
-               cp = (HASH_CURSOR *)dbc->internal;
-               fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu",
-                   P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno,
-                   (u_long)cp->indx);
-               if (F_ISSET(cp, H_DELETED))
-                       fprintf(stderr, " (deleted)");
-               fprintf(stderr, "\n");
-       }
-       MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);
+       cp = (HASH_CURSOR *)dbc->internal;
 
-       return (0);
+       fprintf(stderr, "%#0lx->%#0lx: page: %lu index: %lu",
+           P_TO_ULONG(dbc), P_TO_ULONG(cp), (u_long)cp->pgno,
+           (u_long)cp->indx);
+       if (F_ISSET(cp, H_DELETED))
+               fprintf(stderr, " (deleted)");
+       fprintf(stderr, "\n");
 }
 #endif /* DEBUG */
 
@@ -803,3 +832,75 @@ __ham_dcursor(dbc, pgno, indx)
 
        return (0);
 }
+
+/*
+ * __ham_c_chgpg --
+ *     Adjust the cursors after moving an item to a new page.  We only
+ *     move cursors that are pointing at this one item and are not
+ *     deleted;  since we only touch non-deleted cursors, and since
+ *     (by definition) no item existed at the pgno/indx we're moving the
+ *     item to, we're guaranteed that all the cursors we affect here or
+ *     on abort really do refer to this one item.
+ */
+static int
+__ham_c_chgpg(dbc, old_pgno, old_index, new_pgno, new_index)
+       DBC *dbc;
+       db_pgno_t old_pgno, new_pgno;
+       u_int32_t old_index, new_index;
+{
+       DB *dbp, *ldbp;
+       DB_ENV *dbenv;
+       DB_LSN lsn;
+       DB_TXN *my_txn;
+       DBC *cp;
+       HASH_CURSOR *hcp;
+       int found, ret;
+
+       dbp = dbc->dbp;
+       dbenv = dbp->dbenv;
+
+       my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL;
+       found = 0;
+
+       MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
+       for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
+           ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
+           ldbp = LIST_NEXT(ldbp, dblistlinks)) {
+               MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+               for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
+                   cp = TAILQ_NEXT(cp, links)) {
+                       if (cp == dbc || cp->dbtype != DB_HASH)
+                               continue;
+
+                       hcp = (HASH_CURSOR *)cp->internal;
+
+                       /*
+                        * If a cursor is deleted, it doesn't refer to this
+                        * item--it just happens to have the same indx, but
+                        * it points to a former neighbor.  Don't move it.
+                        */
+                       if (F_ISSET(hcp, H_DELETED))
+                               continue;
+
+                       if (hcp->pgno == old_pgno) {
+                               if (hcp->indx == old_index) {
+                                       hcp->pgno = new_pgno;
+                                       hcp->indx = new_index;
+                               } else
+                                       continue;
+                               if (my_txn != NULL && cp->txn != my_txn)
+                                       found = 1;
+                       }
+               }
+               MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+       }
+       MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
+
+       if (found != 0 && DB_LOGGING(dbc)) {
+               if ((ret = __ham_chgpg_log(dbenv,
+                    my_txn, &lsn, 0, dbp->log_fileid, DB_HAM_CHGPG,
+                    old_pgno, new_pgno, old_index, new_index)) != 0)
+                       return (ret);
+       }
+       return (0);
+}
index 64f3885..a7bc1cd 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997, 1998, 1999, 2000
+ * Copyright (c) 1996-2001
  *     Sleepycat Software.  All rights reserved.
  */
 /*
@@ -43,7 +43,7 @@
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "$Id: hash_page.c,v 11.46 2001/01/11 18:19:51 bostic Exp $";
+static const char revid[] = "Id: hash_page.c,v 11.74 2001/10/20 20:10:01 bostic Exp ";
 #endif /* not lint */
 
 /*
@@ -75,6 +75,9 @@ static const char revid[] = "$Id: hash_page.c,v 11.46 2001/01/11 18:19:51 bostic
 #include "lock.h"
 #include "txn.h"
 
+static int __ham_c_delpg
+    __P((DBC *, db_pgno_t, db_pgno_t, u_int32_t, db_ham_mode, u_int32_t *));
+
 /*
  * PUBLIC: int __ham_item __P((DBC *, db_lockmode_t, db_pgno_t *));
  */
@@ -153,15 +156,18 @@ int
 __ham_item_reset(dbc)
        DBC *dbc;
 {
-       HASH_CURSOR *hcp;
        DB *dbp;
+       DB_MPOOLFILE *mpf;
+       HASH_CURSOR *hcp;
        int ret;
 
-       ret = 0;
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
+
+       ret = 0;
        if (hcp->page != NULL)
-               ret = memp_fput(dbp->mpf, hcp->page, 0);
+               ret = mpf->put(mpf, hcp->page, 0);
 
        __ham_item_init(dbc);
        return (ret);
@@ -181,8 +187,7 @@ __ham_item_init(dbc)
         * If this cursor still holds any locks, we must
         * release them if we are not running with transactions.
         */
-       if (hcp->lock.off != LOCK_INVALID && dbc->txn == NULL)
-           (void)lock_put(dbc->dbp->dbenv, &hcp->lock);
+       (void)__TLPUT(dbc, hcp->lock);
 
        /*
         * The following fields must *not* be initialized here
@@ -191,7 +196,7 @@ __ham_item_init(dbc)
         */
        hcp->bucket = BUCKET_INVALID;
        hcp->lbucket = BUCKET_INVALID;
-       hcp->lock.off = LOCK_INVALID;
+       LOCK_INIT(hcp->lock);
        hcp->lock_mode = DB_LOCK_NG;
        hcp->dup_off = 0;
        hcp->dup_len = 0;
@@ -264,13 +269,12 @@ __ham_item_prev(dbc, mode, pgnop)
        db_lockmode_t mode;
        db_pgno_t *pgnop;
 {
-       DB *dbp;
        HASH_CURSOR *hcp;
        db_pgno_t next_pgno;
        int ret;
 
-       dbp = dbc->dbp;
        hcp = (HASH_CURSOR *)dbc->internal;
+
        /*
         * There are 5 cases for backing up in a hash file.
         * Case 1: In the middle of a page, no duplicates, just dec the index.
@@ -537,25 +541,27 @@ __ham_del_pair(dbc, reclaim_page)
        int reclaim_page;
 {
        DB *dbp;
-       HASH_CURSOR *hcp;
        DBT data_dbt, key_dbt;
        DB_ENV *dbenv;
        DB_LSN new_lsn, *n_lsn, tmp_lsn;
+       DB_MPOOLFILE *mpf;
+       HASH_CURSOR *hcp;
        PAGE *n_pagep, *nn_pagep, *p, *p_pagep;
+       db_ham_mode op;
        db_indx_t ndx;
        db_pgno_t chg_pgno, pgno, tmp_pgno;
        int ret, t_ret;
+       u_int32_t order;
 
        dbp = dbc->dbp;
-       hcp = (HASH_CURSOR *)dbc->internal;
-
        dbenv = dbp->dbenv;
-       ndx = hcp->indx;
-
+       mpf = dbp->mpf;
+       hcp = (HASH_CURSOR *)dbc->internal;
        n_pagep = p_pagep = nn_pagep = NULL;
+       ndx = hcp->indx;
 
-       if (hcp->page == NULL && (ret = memp_fget(dbp->mpf,
-           &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0)
+       if (hcp->page == NULL &&
+           (ret = mpf->get(mpf, &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0)
                return (ret);
        p = hcp->page;
 
@@ -607,10 +613,11 @@ __ham_del_pair(dbc, reclaim_page)
                    dbp->log_fileid, PGNO(p), (u_int32_t)ndx,
                    &LSN(p), &key_dbt, &data_dbt)) != 0)
                        return (ret);
+       } else
+               LSN_NOT_LOGGED(new_lsn);
 
-               /* Move lsn onto page. */
-               LSN(p) = new_lsn;
-       }
+       /* Move lsn onto page. */
+       LSN(p) = new_lsn;
 
        /* Do the delete. */
        __ham_dpair(dbp, p, ndx);
@@ -636,8 +643,11 @@ __ham_del_pair(dbc, reclaim_page)
         * XXX
         * Perhaps we can retain incremental numbers and apply them later.
         */
-       if (!STD_LOCKING(dbc))
+       if (!STD_LOCKING(dbc)) {
                --hcp->hdr->nelem;
+               if ((ret = __ham_dirty_meta(dbc)) != 0)
+                       return (ret);
+       }
 
        /*
         * If we need to reclaim the page, then check if the page is empty.
@@ -650,20 +660,18 @@ __ham_del_pair(dbc, reclaim_page)
        if (!reclaim_page ||
            NUM_ENT(p) != 0 ||
            (PREV_PGNO(p) == PGNO_INVALID && NEXT_PGNO(p) == PGNO_INVALID))
-               return (memp_fset(dbp->mpf, p, DB_MPOOL_DIRTY));
+               return (mpf->set(mpf, p, DB_MPOOL_DIRTY));
 
        if (PREV_PGNO(p) == PGNO_INVALID) {
                /*
                 * First page in chain is empty and we know that there
                 * are more pages in the chain.
                 */
-               if ((ret =
-                   memp_fget(dbp->mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0)
+               if ((ret = mpf->get(mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0)
                        return (ret);
 
-               if (NEXT_PGNO(n_pagep) != PGNO_INVALID &&
-                   (ret = memp_fget(dbp->mpf, &NEXT_PGNO(n_pagep), 0,
-                   &nn_pagep)) != 0)
+               if (NEXT_PGNO(n_pagep) != PGNO_INVALID && (ret =
+                   mpf->get(mpf, &NEXT_PGNO(n_pagep), 0, &nn_pagep)) != 0)
                        goto err;
 
                if (DB_LOGGING(dbc)) {
@@ -676,17 +684,19 @@ __ham_del_pair(dbc, reclaim_page)
                            nn_pagep == NULL ? NULL : &LSN(nn_pagep),
                            &key_dbt)) != 0)
                                goto err;
+               } else
+                       LSN_NOT_LOGGED(new_lsn);
+
+               /* Move lsn onto page. */
+               LSN(p) = new_lsn;       /* Structure assignment. */
+               LSN(n_pagep) = new_lsn;
+               if (NEXT_PGNO(n_pagep) != PGNO_INVALID)
+                       LSN(nn_pagep) = new_lsn;
 
-                       /* Move lsn onto page. */
-                       LSN(p) = new_lsn;       /* Structure assignment. */
-                       LSN(n_pagep) = new_lsn;
-                       if (NEXT_PGNO(n_pagep) != PGNO_INVALID)
-                               LSN(nn_pagep) = new_lsn;
-               }
                if (nn_pagep != NULL) {
                        PREV_PGNO(nn_pagep) = PGNO(p);
-                       if ((ret = memp_fput(dbp->mpf,
-                           nn_pagep, DB_MPOOL_DIRTY)) != 0) {
+                       if ((ret =
+                           mpf->put(mpf, nn_pagep, DB_MPOOL_DIRTY)) != 0) {
                                nn_pagep = NULL;
                                goto err;
                        }
@@ -703,26 +713,30 @@ __ham_del_pair(dbc, reclaim_page)
                 * Update cursors to reflect the fact that records
                 * on the second page have moved to the first page.
                 */
-               if ((ret = __ham_c_chgpg(dbc,
-                   PGNO(n_pagep), NDX_INVALID, PGNO(p), NDX_INVALID)) != 0)
-                       return (ret);
+               if ((ret = __ham_c_delpg(dbc, PGNO(n_pagep),
+                   PGNO(p), 0, DB_HAM_DELFIRSTPG, &order)) != 0)
+                       goto err;
 
                /*
                 * Update the cursor to reflect its new position.
                 */
                hcp->indx = 0;
                hcp->pgno = PGNO(p);
-               if ((ret = memp_fset(dbp->mpf, p, DB_MPOOL_DIRTY)) != 0 ||
-                   (ret = __db_free(dbc, n_pagep)) != 0)
-                       return (ret);
+               hcp->order += order;
+
+               if ((ret = mpf->set(mpf, p, DB_MPOOL_DIRTY)) != 0)
+                       goto err;
+               if ((ret = __db_free(dbc, n_pagep)) != 0) {
+                       n_pagep = NULL;
+                       goto err;
+               }
        } else {
-               if ((ret =
-                   memp_fget(dbp->mpf, &PREV_PGNO(p), 0, &p_pagep)) != 0)
+               if ((ret = mpf->get(mpf, &PREV_PGNO(p), 0, &p_pagep)) != 0)
                        goto err;
 
                if (NEXT_PGNO(p) != PGNO_INVALID) {
-                       if ((ret = memp_fget(dbp->mpf,
-                           &NEXT_PGNO(p), 0, &n_pagep)) != 0)
+                       if ((ret =
+                           mpf->get(mpf, &NEXT_PGNO(p), 0, &n_pagep)) != 0)
                                goto err;
                        n_lsn = &LSN(n_pagep);
                } else {
@@ -740,26 +754,35 @@ __ham_del_pair(dbc, reclaim_page)
                            dbp->log_fileid, PREV_PGNO(p), &LSN(p_pagep),
                            PGNO(p), &LSN(p), NEXT_PGNO(p), n_lsn)) != 0)
                                goto err;
+               } else
+                       LSN_NOT_LOGGED(new_lsn);
+
+               /* Move lsn onto page. */
+               LSN(p_pagep) = new_lsn; /* Structure assignment. */
+               if (n_pagep)
+                       LSN(n_pagep) = new_lsn;
+               LSN(p) = new_lsn;
 
-                       /* Move lsn onto page. */
-                       LSN(p_pagep) = new_lsn; /* Structure assignment. */
-                       if (n_pagep)
-                               LSN(n_pagep) = new_lsn;
-                       LSN(p) = new_lsn;
-               }
                if (NEXT_PGNO(p) == PGNO_INVALID) {
                        /*
                         * There is no next page; put the cursor on the
                         * previous page as if we'd deleted the last item
-                        * on that page; index greater than number of
-                        * valid entries and H_DELETED set.
+                        * on that page, with index after the last valid
+                        * entry.
+                        *
+                        * The deleted flag was set up above.
                         */
                        hcp->pgno = PGNO(p_pagep);
                        hcp->indx = NUM_ENT(p_pagep);
-                       F_SET(hcp, H_DELETED);
+                       op = DB_HAM_DELLASTPG;
                } else {
+                       /*
+                        * There is a next page, so put the cursor at
+                        * the beginning of it.
+                        */
                        hcp->pgno = NEXT_PGNO(p);
                        hcp->indx = 0;
+                       op = DB_HAM_DELMIDPG;
                }
 
                /*
@@ -770,26 +793,28 @@ __ham_del_pair(dbc, reclaim_page)
                hcp->page = NULL;
                chg_pgno = PGNO(p);
                ret = __db_free(dbc, p);
-               if ((t_ret = memp_fput(dbp->mpf, p_pagep, DB_MPOOL_DIRTY)) != 0
-                   && ret == 0)
+               if ((t_ret =
+                   mpf->put(mpf, p_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)
                        ret = t_ret;
-               if (n_pagep != NULL && (t_ret = memp_fput(dbp->mpf,
-                   n_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)
+               if (n_pagep != NULL && (t_ret =
+                   mpf->put(mpf, n_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)
                        ret = t_ret;
                if (ret != 0)
                        return (ret);
-               ret = __ham_c_chgpg(dbc,
-                   chg_pgno, 0, hcp->pgno, hcp->indx);
+               if ((ret = __ham_c_delpg(dbc,
+                   chg_pgno, hcp->pgno, hcp->indx, op, &order)) != 0)
+                       return (ret);
+               hcp->order += order;
        }
        return (ret);
 
 err:   /* Clean up any pages. */
        if (n_pagep != NULL)
-               (void)memp_fput(dbp->mpf, n_pagep, 0);
+               (void)mpf->put(mpf, n_pagep, 0);
        if (nn_pagep != NULL)
-               (void)memp_fput(dbp->mpf, nn_pagep, 0);
+               (void)mpf->put(mpf, nn_pagep, 0);
        if (p_pagep != NULL)
-               (void)memp_fput(dbp->mpf, p_pagep, 0);
+               (void)mpf->put(mpf, p_pagep, 0);
        return (ret);
 }
 
@@ -811,8 +836,8 @@ __ham_replpair(dbc, dbt, make_dup)
        DBT old_dbt, tdata, tmp;
        DB_LSN  new_lsn;
        int32_t change;                 /* XXX: Possible overflow. */
-       u_int32_t dup, len, memsize;
-       int is_big, ret, type;
+       u_int32_t dup_flag, len, memsize;
+       int beyond_eor, is_big, ret, type;
        u_int8_t *beg, *dest, *end, *hk, *src;
        void *memp;
 
@@ -850,10 +875,11 @@ __ham_replpair(dbc, dbt, make_dup)
                len = LEN_HKEYDATA(hcp->page,
                    dbp->pgsize, H_DATAINDEX(hcp->indx));
 
-       if (dbt->doff + dbt->dlen > len)
+       beyond_eor = dbt->doff + dbt->dlen > len;
+       if (beyond_eor)
                change += dbt->doff + dbt->dlen - len;
 
-       if (change > (int32_t)P_FREESPACE(hcp->page) || is_big) {
+       if (change > (int32_t)P_FREESPACE(hcp->page) || beyond_eor || is_big) {
                /*
                 * Case 3 -- two subcases.
                 * A. This is not really a partial operation, but an overwrite.
@@ -868,16 +894,16 @@ __ham_replpair(dbc, dbt, make_dup)
                memset(&tmp, 0, sizeof(tmp));
                if ((ret =
                    __db_ret(dbp, hcp->page, H_KEYINDEX(hcp->indx),
-                   &tmp, &dbc->rkey.data, &dbc->rkey.ulen)) != 0)
+                   &tmp, &dbc->rkey->data, &dbc->rkey->ulen)) != 0)
                        return (ret);
 
                /* Preserve duplicate info. */
-               dup = F_ISSET(hcp, H_ISDUP);
+               dup_flag = F_ISSET(hcp, H_ISDUP);
                if (dbt->doff == 0 && dbt->dlen == len) {
                        ret = __ham_del_pair(dbc, 0);
                        if (ret == 0)
                            ret = __ham_add_el(dbc,
-                               &tmp, dbt, dup ? H_DUPLICATE : H_KEYDATA);
+                               &tmp, dbt, dup_flag ? H_DUPLICATE : H_KEYDATA);
                } else {                                        /* Case B */
                        type = HPAGE_PTYPE(hk) != H_OFFPAGE ?
                            HPAGE_PTYPE(hk) : H_KEYDATA;
@@ -891,15 +917,14 @@ __ham_replpair(dbc, dbt, make_dup)
 
                        /* Now we can delete the item. */
                        if ((ret = __ham_del_pair(dbc, 0)) != 0) {
-                               __os_free(memp, memsize);
+                               __os_free(dbp->dbenv, memp, memsize);
                                goto err;
                        }
 
                        /* Now shift old data around to make room for new. */
                        if (change > 0) {
                                 if ((ret = __os_realloc(dbp->dbenv,
-                                    tdata.size + change,
-                                    NULL, &tdata.data)) != 0)
+                                    tdata.size + change, &tdata.data)) != 0)
                                        return (ret);
                                memp = tdata.data;
                                memsize = tdata.size + change;
@@ -920,9 +945,9 @@ __ham_replpair(dbc, dbt, make_dup)
 
                        /* Now add the pair. */
                        ret = __ham_add_el(dbc, &tmp, &tdata, type);
-                       __os_free(memp, memsize);
+                       __os_free(dbp->dbenv, memp, memsize);
                }
-               F_SET(hcp, dup);
+               F_SET(hcp, dup_flag);
 err:           return (ret);
        }
 
@@ -947,8 +972,10 @@ err:               return (ret);
                    (u_int32_t)dbt->doff, &old_dbt, dbt, make_dup)) != 0)
                        return (ret);
 
-               LSN(hcp->page) = new_lsn;       /* Structure assignment. */
-       }
+       } else
+               LSN_NOT_LOGGED(new_lsn);
+
+       LSN(hcp->page) = new_lsn;       /* Structure assignment. */
 
        __ham_onpage_replace(hcp->page, dbp->pgsize,
            (u_int32_t)H_DATAINDEX(hcp->indx), (int32_t)dbt->doff, change, dbt);
@@ -1022,10 +1049,12 @@ __ham_split_page(dbc, obucket, nbucket)
 {
        DB *dbp;
        DBC **carray;
-       HASH_CURSOR *hcp, *cp;
        DBT key, page_dbt;
        DB_ENV *dbenv;
+       DB_LOCK block;
        DB_LSN new_lsn;
+       DB_MPOOLFILE *mpf;
+       HASH_CURSOR *hcp, *cp;
        PAGE **pp, *old_pagep, *temp_pagep, *new_pagep;
        db_indx_t n;
        db_pgno_t bucket_pgno, npgno, next_pgno;
@@ -1034,22 +1063,24 @@ __ham_split_page(dbc, obucket, nbucket)
        void *big_buf;
 
        dbp = dbc->dbp;
-       hcp = (HASH_CURSOR *)dbc->internal;
        dbenv = dbp->dbenv;
+       mpf = dbp->mpf;
+       hcp = (HASH_CURSOR *)dbc->internal;
        temp_pagep = old_pagep = new_pagep = NULL;
-
-       if ((ret = __ham_get_clist(dbp, obucket, NDX_INVALID, &carray)) != 0)
-               return (ret);
+       carray = NULL;
+       LOCK_INIT(block);
 
        bucket_pgno = BUCKET_TO_PAGE(hcp, obucket);
-       if ((ret = memp_fget(dbp->mpf,
+       if ((ret = __db_lget(dbc,
+           0, bucket_pgno, DB_LOCK_WRITE, 0, &block)) != 0)
+               goto err;
+       if ((ret = mpf->get(mpf,
            &bucket_pgno, DB_MPOOL_CREATE, &old_pagep)) != 0)
                goto err;
 
        /* Properly initialize the new bucket page. */
        npgno = BUCKET_TO_PAGE(hcp, nbucket);
-       if ((ret = memp_fget(dbp->mpf,
-           &npgno, DB_MPOOL_CREATE, &new_pagep)) != 0)
+       if ((ret = mpf->get(mpf, &npgno, DB_MPOOL_CREATE, &new_pagep)) != 0)
                goto err;
        P_INIT(new_pagep,
            dbp->pgsize, npgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
@@ -1064,26 +1095,28 @@ __ham_split_page(dbc, obucket, nbucket)
                    dbc->txn, &new_lsn, 0, dbp->log_fileid, SPLITOLD,
                    PGNO(old_pagep), &page_dbt, &LSN(old_pagep))) != 0)
                        goto err;
-       }
+       } else
+               LSN_NOT_LOGGED(new_lsn);
+
+       LSN(old_pagep) = new_lsn;       /* Structure assignment. */
 
        P_INIT(old_pagep, dbp->pgsize, PGNO(old_pagep), PGNO_INVALID,
            PGNO_INVALID, 0, P_HASH);
 
-       if (DB_LOGGING(dbc))
-               LSN(old_pagep) = new_lsn;       /* Structure assignment. */
-
        big_len = 0;
        big_buf = NULL;
        key.flags = 0;
        while (temp_pagep != NULL) {
+               if ((ret = __ham_get_clist(dbp,
+                   PGNO(temp_pagep), NDX_INVALID, &carray)) != 0)
+                       goto err;
+
                for (n = 0; n < (db_indx_t)NUM_ENT(temp_pagep); n += 2) {
-                       if ((ret =
-                           __db_ret(dbp, temp_pagep, H_KEYINDEX(n),
-                           &key, &big_buf, &big_len)) != 0)
+                       if ((ret = __db_ret(dbp, temp_pagep,
+                           H_KEYINDEX(n), &key, &big_buf, &big_len)) != 0)
                                goto err;
 
-                       if (__ham_call_hash(dbc, key.data, key.size)
-                           == obucket)
+                       if (__ham_call_hash(dbc, key.data, key.size) == obucket)
                                pp = &old_pagep;
                        else
                                pp = &new_pagep;
@@ -1092,7 +1125,6 @@ __ham_split_page(dbc, obucket, nbucket)
                         * Figure out how many bytes we need on the new
                         * page to store the key/data pair.
                         */
-
                        len = LEN_HITEM(temp_pagep, dbp->pgsize,
                            H_DATAINDEX(n)) +
                            LEN_HITEM(temp_pagep, dbp->pgsize,
@@ -1109,8 +1141,9 @@ __ham_split_page(dbc, obucket, nbucket)
                                            SPLITNEW, PGNO(*pp), &page_dbt,
                                            &LSN(*pp))) != 0)
                                                goto err;
-                                       LSN(*pp) = new_lsn;
-                               }
+                               } else
+                                       LSN_NOT_LOGGED(new_lsn);
+                               LSN(*pp) = new_lsn;
                                if ((ret =
                                    __ham_add_ovflpage(dbc, *pp, 1, pp)) != 0)
                                        goto err;
@@ -1156,23 +1189,30 @@ __ham_split_page(dbc, obucket, nbucket)
 
                if (next_pgno == PGNO_INVALID)
                        temp_pagep = NULL;
-               else if ((ret = memp_fget(dbp->mpf,
-                   &next_pgno, DB_MPOOL_CREATE, &temp_pagep)) != 0)
+               else if ((ret = mpf->get(
+                   mpf, &next_pgno, DB_MPOOL_CREATE, &temp_pagep)) != 0)
                        goto err;
 
-               if (temp_pagep != NULL && DB_LOGGING(dbc)) {
-                       page_dbt.size = dbp->pgsize;
-                       page_dbt.data = temp_pagep;
-                       if ((ret = __ham_splitdata_log(dbenv,
-                           dbc->txn, &new_lsn, 0, dbp->log_fileid,
-                           SPLITOLD, PGNO(temp_pagep),
-                           &page_dbt, &LSN(temp_pagep))) != 0)
-                               goto err;
+               if (temp_pagep != NULL) {
+                       if (DB_LOGGING(dbc)) {
+                               page_dbt.size = dbp->pgsize;
+                               page_dbt.data = temp_pagep;
+                               if ((ret = __ham_splitdata_log(dbenv,
+                                   dbc->txn, &new_lsn, 0, dbp->log_fileid,
+                                   SPLITOLD, PGNO(temp_pagep),
+                                   &page_dbt, &LSN(temp_pagep))) != 0)
+                                       goto err;
+                       } else
+                               LSN_NOT_LOGGED(new_lsn);
                        LSN(temp_pagep) = new_lsn;
                }
+
+               if (carray != NULL)     /* We never knew its size. */
+                       __os_free(dbp->dbenv, carray, 0);
+               carray = NULL;
        }
        if (big_buf != NULL)
-               __os_free(big_buf, big_len);
+               __os_free(dbenv, big_buf, big_len);
 
        /*
         * If the original bucket spanned multiple pages, then we've got
@@ -1203,22 +1243,28 @@ __ham_split_page(dbc, obucket, nbucket)
                    &LSN(new_pagep))) != 0)
                        goto err;
                LSN(new_pagep) = new_lsn;
+       } else {
+               LSN_NOT_LOGGED(LSN(old_pagep));
+               LSN_NOT_LOGGED(LSN(new_pagep));
        }
-       ret = memp_fput(dbp->mpf, old_pagep, DB_MPOOL_DIRTY);
-       if ((t_ret = memp_fput(dbp->mpf, new_pagep, DB_MPOOL_DIRTY)) != 0
-           && ret == 0)
+
+       ret = mpf->put(mpf, old_pagep, DB_MPOOL_DIRTY);
+       if ((t_ret =
+           mpf->put(mpf, new_pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)
                ret = t_ret;
 
        if (0) {
 err:           if (old_pagep != NULL)
-                       (void)memp_fput(dbp->mpf, old_pagep, DB_MPOOL_DIRTY);
+                       (void)mpf->put(mpf, old_pagep, DB_MPOOL_DIRTY);
                if (new_pagep != NULL)
-                       (void)memp_fput(dbp->mpf, new_pagep, DB_MPOOL_DIRTY);
+                       (void)mpf->put(mpf, new_pagep, DB_MPOOL_DIRTY);
                if (temp_pagep != NULL && PGNO(temp_pagep) != bucket_pgno)
-                       (void)memp_fput(dbp->mpf, temp_pagep, DB_MPOOL_DIRTY);
+                       (void)mpf->put(mpf, temp_pagep, DB_MPOOL_DIRTY);
        }
+       if (LOCK_ISSET(block))
+               __TLPUT(dbc, block);
        if (carray != NULL)             /* We never knew its size. */
-               __os_free(carray, 0);
+               __os_free(dbp->dbenv, carray, 0);
        return (ret);
 }
 
@@ -1237,11 +1283,12 @@ __ham_add_el(dbc, key, val, type)
        const DBT *key, *val;
        int type;
 {
-       DB *dbp;
-       HASH_CURSOR *hcp;
        const DBT *pkey, *pdata;
+       DB *dbp;
        DBT key_dbt, data_dbt;
        DB_LSN new_lsn;
+       DB_MPOOLFILE *mpf;
+       HASH_CURSOR *hcp;
        HOFFPAGE doff, koff;
        db_pgno_t next_pgno, pgno;
        u_int32_t data_size, key_size, pairsize, rectype;
@@ -1249,13 +1296,14 @@ __ham_add_el(dbc, key, val, type)
        int key_type, data_type;
 
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
        do_expand = 0;
 
-       pgno = hcp->seek_found_page != PGNO_INVALID ?  hcp->seek_found_page :
-           hcp->pgno;
-       if (hcp->page == NULL && (ret = memp_fget(dbp->mpf, &pgno,
-           DB_MPOOL_CREATE, &hcp->page)) != 0)
+       pgno = hcp->seek_found_page != PGNO_INVALID ?
+           hcp->seek_found_page : hcp->pgno;
+       if (hcp->page == NULL &&
+           (ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &hcp->page)) != 0)
                return (ret);
 
        key_size = HKEYDATA_PSIZE(key->size);
@@ -1279,8 +1327,7 @@ __ham_add_el(dbc, key, val, type)
                if (P_FREESPACE(hcp->page) >= pairsize)
                        break;
                next_pgno = NEXT_PGNO(hcp->page);
-               if ((ret =
-                   __ham_next_cpage(dbc, next_pgno, 0)) != 0)
+               if ((ret = __ham_next_cpage(dbc, next_pgno, 0)) != 0)
                        return (ret);
        }
 
@@ -1290,7 +1337,7 @@ __ham_add_el(dbc, key, val, type)
        if (P_FREESPACE(hcp->page) < pairsize) {
                do_expand = 1;
                if ((ret = __ham_add_ovflpage(dbc,
-                   (PAGE *)hcp->page, 1, (PAGE **)&hcp->page)) !=  0)
+                   (PAGE *)hcp->page, 1, (PAGE **)&hcp->page)) != 0)
                        return (ret);
                hcp->pgno = PGNO(hcp->page);
        }
@@ -1348,10 +1395,11 @@ __ham_add_el(dbc, key, val, type)
                    (u_int32_t)NUM_ENT(hcp->page), &LSN(hcp->page), pkey,
                    pdata)) != 0)
                        return (ret);
+       } else
+               LSN_NOT_LOGGED(new_lsn);
 
-               /* Move lsn onto page. */
-               LSN(hcp->page) = new_lsn;       /* Structure assignment. */
-       }
+       /* Move lsn onto page. */
+       LSN(hcp->page) = new_lsn;       /* Structure assignment. */
 
        __ham_putitem(hcp->page, pkey, key_type);
        __ham_putitem(hcp->page, pdata, data_type);
@@ -1369,8 +1417,11 @@ __ham_add_el(dbc, key, val, type)
         * XXX
         * Maybe keep incremental numbers here.
         */
-       if (!STD_LOCKING(dbc))
+       if (!STD_LOCKING(dbc)) {
                hcp->hdr->nelem++;
+               if ((ret = __ham_dirty_meta(dbc)) != 0)
+                       return (ret);
+       }
 
        if (do_expand || (hcp->hdr->ffactor != 0 &&
            (u_int32_t)H_NUMPAIRS(hcp->page) > hcp->hdr->ffactor))
@@ -1427,13 +1478,13 @@ __ham_add_ovflpage(dbc, pagep, release, pp)
        PAGE **pp;
 {
        DB *dbp;
-       HASH_CURSOR *hcp;
        DB_LSN new_lsn;
+       DB_MPOOLFILE *mpf;
        PAGE *new_pagep;
        int ret;
 
        dbp = dbc->dbp;
-       hcp = (HASH_CURSOR *)dbc->internal;
+       mpf = dbp->mpf;
 
        if ((ret = __db_new(dbc, P_HASH, &new_pagep)) != 0)
                return (ret);
@@ -1443,15 +1494,17 @@ __ham_add_ovflpage(dbc, pagep, release, pp)
                    PUTOVFL, dbp->log_fileid, PGNO(pagep), &LSN(pagep),
                    PGNO(new_pagep), &LSN(new_pagep), PGNO_INVALID, NULL)) != 0)
                        return (ret);
+       } else
+               LSN_NOT_LOGGED(new_lsn);
 
-               /* Move lsn onto page. */
-               LSN(pagep) = LSN(new_pagep) = new_lsn;
-       }
+       /* Move lsn onto page. */
+       LSN(pagep) = LSN(new_pagep) = new_lsn;
        NEXT_PGNO(pagep) = PGNO(new_pagep);
+
        PREV_PGNO(new_pagep) = PGNO(pagep);
 
        if (release)
-               ret = memp_fput(dbp->mpf, pagep, DB_MPOOL_DIRTY);
+               ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY);
 
        *pp = new_pagep;
        return (ret);
@@ -1467,10 +1520,12 @@ __ham_get_cpage(dbc, mode)
 {
        DB *dbp;
        DB_LOCK tmp_lock;
+       DB_MPOOLFILE *mpf;
        HASH_CURSOR *hcp;
        int ret;
 
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
        ret = 0;
 
@@ -1485,25 +1540,22 @@ __ham_get_cpage(dbc, mode)
         * 4. If there is a lock, but it's for a different bucket, then we need
         *    to release the existing lock and get a new lock.
         */
-       tmp_lock.off = LOCK_INVALID;
+       LOCK_INIT(tmp_lock);
        if (STD_LOCKING(dbc)) {
-               if (hcp->lock.off != LOCK_INVALID &&
-                   hcp->lbucket != hcp->bucket) {              /* Case 4 */
-                       if (dbc->txn == NULL &&
-                           (ret = lock_put(dbp->dbenv, &hcp->lock)) != 0)
-                               return (ret);
-                       hcp->lock.off = LOCK_INVALID;
-               }
-               if ((hcp->lock.off != LOCK_INVALID &&
+               if (hcp->lbucket != hcp->bucket &&      /* Case 4 */
+                   (ret = __TLPUT(dbc, hcp->lock)) != 0)
+                       return (ret);
+
+               if ((LOCK_ISSET(hcp->lock) &&
                    (hcp->lock_mode == DB_LOCK_READ &&
                    mode == DB_LOCK_WRITE))) {
                        /* Case 3. */
                        tmp_lock = hcp->lock;
-                       hcp->lock.off = LOCK_INVALID;
+                       LOCK_INIT(hcp->lock);
                }
 
                /* Acquire the lock. */
-               if (hcp->lock.off == LOCK_INVALID)
+               if (!LOCK_ISSET(hcp->lock))
                        /* Cases 1, 3, and 4. */
                        if ((ret = __ham_lock_bucket(dbc, mode)) != 0)
                                return (ret);
@@ -1511,17 +1563,18 @@ __ham_get_cpage(dbc, mode)
                if (ret == 0) {
                        hcp->lock_mode = mode;
                        hcp->lbucket = hcp->bucket;
-                       if (tmp_lock.off != LOCK_INVALID)
+                       if (LOCK_ISSET(tmp_lock))
                                /* Case 3: release the original lock. */
-                               ret = lock_put(dbp->dbenv, &tmp_lock);
-               } else if (tmp_lock.off != LOCK_INVALID)
+                               ret =
+                                   dbp->dbenv->lock_put(dbp->dbenv, &tmp_lock);
+               } else if (LOCK_ISSET(tmp_lock))
                        hcp->lock = tmp_lock;
        }
 
        if (ret == 0 && hcp->page == NULL) {
                if (hcp->pgno == PGNO_INVALID)
                        hcp->pgno = BUCKET_TO_PAGE(hcp, hcp->bucket);
-               if ((ret = memp_fget(dbp->mpf,
+               if ((ret = mpf->get(mpf,
                    &hcp->pgno, DB_MPOOL_CREATE, &hcp->page)) != 0)
                        return (ret);
        }
@@ -1543,18 +1596,21 @@ __ham_next_cpage(dbc, pgno, dirty)
        int dirty;
 {
        DB *dbp;
+       DB_MPOOLFILE *mpf;
        HASH_CURSOR *hcp;
        PAGE *p;
        int ret;
 
        dbp = dbc->dbp;
+       mpf = dbp->mpf;
        hcp = (HASH_CURSOR *)dbc->internal;
 
-       if (hcp->page != NULL && (ret = memp_fput(dbp->mpf,
-           hcp->page, dirty ? DB_MPOOL_DIRTY : 0)) != 0)
+       if (hcp->page != NULL &&
+           (ret = mpf->put(mpf, hcp->page, dirty ? DB_MPOOL_DIRTY : 0)) != 0)
                return (ret);
+       hcp->page = NULL;
 
-       if ((ret = memp_fget(dbp->mpf, &pgno, DB_MPOOL_CREATE, &p)) != 0)
+       if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &p)) != 0)
                return (ret);
 
        hcp->page = p;
@@ -1576,7 +1632,7 @@ __ham_lock_bucket(dbc, mode)
        db_lockmode_t mode;
 {
        HASH_CURSOR *hcp;
-       u_int32_t flags;
+       db_pgno_t pgno;
        int gotmeta, ret;
 
        hcp = (HASH_CURSOR *)dbc->internal;
@@ -1584,17 +1640,12 @@ __ham_lock_bucket(dbc, mode)
        if (gotmeta)
                if ((ret = __ham_get_meta(dbc)) != 0)
                        return (ret);
-       dbc->lock.pgno = BUCKET_TO_PAGE(hcp, hcp->bucket);
+       pgno = BUCKET_TO_PAGE(hcp, hcp->bucket);
        if (gotmeta)
                if ((ret = __ham_release_meta(dbc)) != 0)
                        return (ret);
 
-       flags = 0;
-       if (DB_NONBLOCK(dbc))
-               LF_SET(DB_LOCK_NOWAIT);
-
-       ret = lock_get(dbc->dbp->dbenv,
-                   dbc->locker, flags, &dbc->lock_dbt, mode, &hcp->lock);
+       ret = __db_lget(dbc, 0, pgno, mode, 0, &hcp->lock);
 
        hcp->lock_mode = mode;
        return (ret);
@@ -1606,6 +1657,9 @@ __ham_lock_bucket(dbc, mode)
  *     represents.  The caller is responsible for freeing up duplicates
  *     or offpage entries that might be referenced by this pair.
  *
+ *     Recovery assumes that this may be called without the metadata
+ *     page pinned.
+ *
  * PUBLIC: void __ham_dpair __P((DB *, PAGE *, u_int32_t));
  */
 void
@@ -1653,3 +1707,152 @@ __ham_dpair(dbp, p, indx)
                p->inp[n] = p->inp[n + 2] + delta;
 
 }
+
+/*
+ * __ham_c_delpg --
+ *
+ * Adjust the cursors after we've emptied a page in a bucket, taking
+ * care that when we move cursors pointing to deleted items, their
+ * orders don't collide with the orders of cursors on the page we move
+ * them to (since after this function is called, cursors with the same
+ * index on the two pages will be otherwise indistinguishable--they'll
+ * all have pgno new_pgno).  There are three cases:
+ *
+ *     1) The emptied page is the first page in the bucket.  In this
+ *     case, we've copied all the items from the second page into the
+ *     first page, so the first page is new_pgno and the second page is
+ *     old_pgno.  new_pgno is empty, but can have deleted cursors
+ *     pointing at indx 0, so we need to be careful of the orders
+ *     there.  This is DB_HAM_DELFIRSTPG.
+ *
+ *     2) The page is somewhere in the middle of a bucket.  Our caller
+ *     can just delete such a page, so it's old_pgno.  old_pgno is
+ *     empty, but may have deleted cursors pointing at indx 0, so we
+ *     need to be careful of indx 0 when we move those cursors to
+ *     new_pgno.  This is DB_HAM_DELMIDPG.
+ *
+ *     3) The page is the last in a bucket.  Again the empty page is
+ *     old_pgno, and again it should only have cursors that are deleted
+ *     and at indx == 0.  This time, though, there's no next page to
+ *     move them to, so we set them to indx == num_ent on the previous
+ *     page--and indx == num_ent is the index whose cursors we need to
+ *     be careful of.  This is DB_HAM_DELLASTPG.
+ */
+static int
+__ham_c_delpg(dbc, old_pgno, new_pgno, num_ent, op, orderp)
+       DBC *dbc;
+       db_pgno_t old_pgno, new_pgno;
+       u_int32_t num_ent;
+       db_ham_mode op;
+       u_int32_t *orderp;
+{
+       DB *dbp, *ldbp;
+       DB_ENV *dbenv;
+       DB_LSN lsn;
+       DB_TXN *my_txn;
+       DBC *cp;
+       HASH_CURSOR *hcp;
+       int found, ret;
+       db_indx_t indx;
+       u_int32_t order;
+
+       /* Which is the worrisome index? */
+       indx = (op == DB_HAM_DELLASTPG) ? num_ent : 0;
+
+       dbp = dbc->dbp;
+       dbenv = dbp->dbenv;
+
+       my_txn = IS_SUBTRANSACTION(dbc->txn) ? dbc->txn : NULL;
+       found = 0;
+
+       MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
+       /*
+        * Find the highest order of any cursor our movement
+        * may collide with.
+        */
+       order = 1;
+       for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
+           ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
+           ldbp = LIST_NEXT(ldbp, dblistlinks)) {
+               MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+               for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
+                   cp = TAILQ_NEXT(cp, links)) {
+                       if (cp == dbc || cp->dbtype != DB_HASH)
+                               continue;
+                       hcp = (HASH_CURSOR *)cp->internal;
+                       if (hcp->pgno == new_pgno) {
+                               if (hcp->indx == indx &&
+                                   F_ISSET(hcp, H_DELETED) &&
+                                   hcp->order >= order)
+                                       order = hcp->order + 1;
+                               DB_ASSERT(op != DB_HAM_DELFIRSTPG ||
+                                   hcp->indx == NDX_INVALID ||
+                                   (hcp->indx == 0 &&
+                                   F_ISSET(hcp, H_DELETED)));
+                       }
+               }
+               MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+       }
+
+       for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
+           ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
+           ldbp = LIST_NEXT(ldbp, dblistlinks)) {
+               MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
+               for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
+                   cp = TAILQ_NEXT(cp, links)) {
+                       if (cp == dbc || cp->dbtype != DB_HASH)
+                               continue;
+
+                       hcp = (HASH_CURSOR *)cp->internal;
+
+                       if (hcp->pgno == old_pgno) {
+                               switch (op) {
+                               case DB_HAM_DELFIRSTPG:
+                                       /*
+                                        * We're moving all items,
+                                        * regardless of index.
+                                        */
+                                       hcp->pgno = new_pgno;
+
+                                       /*
+                                        * But we have to be careful of
+                                        * the order values.
+                                        */
+                                       if (hcp->indx == indx)
+                                               hcp->order += order;
+                                       break;
+                               case DB_HAM_DELMIDPG:
+                                       hcp->pgno = new_pgno;
+                                       DB_ASSERT(hcp->indx == 0 &&
+                                           F_ISSET(hcp, H_DELETED));
+                                       hcp->order += order;
+                                       break;
+                               case DB_HAM_DELLASTPG:
+                                       hcp->pgno = new_pgno;
+                                       DB_ASSERT(hcp->indx == 0 &&
+                                           F_ISSET(hcp, H_DELETED));
+                                       hcp->indx = indx;
+                                       hcp->order += order;
+                                       break;
+                               default:
+                                       DB_ASSERT(0);
+                                       return (__db_panic(dbp->dbenv, EINVAL));
+                               }
+                               if (my_txn != NULL && cp->txn != my_txn)
+                                       found = 1;
+                       }
+               }
+               MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
+       }
+       MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
+
+       if (found != 0 && DB_LOGGING(dbc)) {
+               if ((ret = __ham_chgpg_log(dbenv,
+                    my_txn, &lsn, 0, dbp->log_fileid, op,
+                    old_pgno, new_pgno, indx, order)) != 0)
+                       return (ret);
+       }
+       *orderp = order;
+       return (0);
+}
+
index 712289b..3d79c2b 100644 (file)
@@ -39,6 +39,7 @@ void headerMergeLegacySigs(Header h, const Header sig)
         ptr = hfd(ptr, type))
     {
        switch (tag) {
+       /* XXX Translate legacy signature tag values. */
        case RPMSIGTAG_SIZE:
            tag = RPMTAG_SIGSIZE;
            /*@switchbreak@*/ break;
@@ -60,6 +61,11 @@ void headerMergeLegacySigs(Header h, const Header sig)
        case RPMSIGTAG_PGP5:
            tag = RPMTAG_SIGPGP5;
            /*@switchbreak@*/ break;
+       case RPMSIGTAG_PAYLOADSIZE:
+           tag = RPMTAG_ARCHIVESIZE;
+           /*@switchbreak@*/ break;
+       case RPMSIGTAG_SHA1:
+       case RPMSIGTAG_DSA:
        default:
            if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
                continue;
@@ -88,6 +94,7 @@ Header headerRegenSigHeader(const Header h)
         ptr = hfd(ptr, type))
     {
        switch (tag) {
+       /* XXX Translate legacy signature tag values. */
        case RPMTAG_SIGSIZE:
            stag = RPMSIGTAG_SIZE;
            /*@switchbreak@*/ break;
@@ -109,6 +116,11 @@ Header headerRegenSigHeader(const Header h)
        case RPMTAG_SIGPGP5:
            stag = RPMSIGTAG_PGP5;
            /*@switchbreak@*/ break;
+       case RPMTAG_ARCHIVESIZE:
+           stag = RPMSIGTAG_PAYLOADSIZE;
+           /*@switchbreak@*/ break;
+       case RPMTAG_SHA1HEADER:
+       case RPMTAG_DSAHEADER:
        default:
            if (!(tag >= HEADER_SIGBASE && tag < HEADER_TAGBASE))
                continue;
@@ -249,6 +261,7 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd,
        /*@notreached@*/ break;
     }
 
+    /* Read the signature header. */
     rc = rpmReadSignature(fd, &sig, l->signature_type);
     if (!(rc == RPMRC_OK || rc == RPMRC_BADSIZE)) {
        rpmError(RPMERR_SIGGEN, _("%s: rpmReadSignature failed\n"), fn);
@@ -260,24 +273,26 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd,
        goto exit;
     }
 
-    if (!ts->verify_legacy)    /* leave fd ready to install payload */
-       ts->sigtag = 0;
-    else if (headerIsEntry(sig, RPMSIGTAG_GPG))
+    /* Figger the most effective available signature. */
+    if (headerIsEntry(sig, RPMSIGTAG_DSA))
+       ts->sigtag = RPMSIGTAG_DSA;
+    else if (!ts->verify_legacy)       /* leave fd ready to install payload */
+       ts->sigtag = (headerIsEntry(sig, RPMSIGTAG_SHA1)) ? RPMSIGTAG_SHA1 : 0;
+    else if (headerIsEntry(sig, RPMSIGTAG_GPG)) {
        ts->sigtag = RPMSIGTAG_GPG;
-    else if (headerIsEntry(sig, RPMSIGTAG_PGP))
+       fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
+    } else if (headerIsEntry(sig, RPMSIGTAG_PGP)) {
        ts->sigtag = RPMSIGTAG_PGP;
-    else if (headerIsEntry(sig, RPMSIGTAG_MD5))
+       fdInitDigest(fd, PGPHASHALGO_MD5, 0);
+    } else if (headerIsEntry(sig, RPMSIGTAG_SHA1)) {
+       ts->sigtag = RPMSIGTAG_SHA1;    /* XXX never happens */
+    } else if (headerIsEntry(sig, RPMSIGTAG_MD5)) {
        ts->sigtag = RPMSIGTAG_MD5;
-    else
-       ts->sigtag = 0;
-
-    /*@-type@*/ /* FIX: cast? */
-    if (ts->sigtag == RPMSIGTAG_GPG)
-       fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
-    else if (ts->sigtag == RPMSIGTAG_PGP || ts->sigtag == RPMSIGTAG_MD5)
        fdInitDigest(fd, PGPHASHALGO_MD5, 0);
-    /*@=type@*/
+    } else
+       ts->sigtag = 0;                 /* XXX never happens */
 
+    /* Read the metadata, computing digest(s) on the fly. */
     hmagic = ((l->major >= 3) ? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
     h = headerRead(fd, hmagic);
     if (h == NULL) {
@@ -293,56 +308,94 @@ int rpmReadPackageFile(rpmTransactionSet ts, FD_t fd,
     }
 
     ts->dig = pgpNewDig();
-    ts->dig->nbytes = headerSizeof(h, hmagic);
-
-    /* Read the compressed payload. */
-    while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
-       ts->dig->nbytes += count;
-
-    if (count < 0) {
-       rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
-       rc = RPMRC_FAIL;
+    if (ts->dig == NULL) {
+       rc = RPMRC_OK;          /* XXX WRONG */
        goto exit;
     }
-    ts->dig->nbytes += count;
+    ts->dig->nbytes = 0;
 
+    /* Retrieve the tag parameters from the signature header. */
+    ts->sig = NULL;
     xx = headerGetEntry(sig, ts->sigtag, &ts->sigtype,
                (void **) &ts->sig, &ts->siglen);
+    if (ts->sig == NULL) {
+       rc = RPMRC_OK;          /* XXX WRONG */
+       goto exit;
+    }
 
-    xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug());
-
-    /*@-type@*/ /* FIX: cast? */
-    for (i = fd->ndigests - 1; i >= 0; i--) {
-       FDDIGEST_t fddig = fd->digests + i;
-       if (fddig->hashctx == NULL)
-           continue;
-       if (fddig->hashalgo == PGPHASHALGO_MD5) {
-           /*@-branchstate@*/
-           if (ts->dig->md5ctx != NULL)
-               (void) rpmDigestFinal(ts->dig->md5ctx, NULL, NULL, 0);
-           /*@=branchstate@*/
-           ts->dig->md5ctx = fddig->hashctx;
-           fddig->hashctx = NULL;
-           continue;
+    switch (ts->sigtag) {
+    case RPMSIGTAG_DSA:
+       /* Parse the parameters from the OpenPGP packets that will be needed. */
+       xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug());
+       /*@fallthrough@*/
+    case RPMSIGTAG_SHA1:
+    {  void * uh = NULL;
+       int_32 uht;
+       int_32 uhc;
+
+       /*@-branchstate@*/
+       if (headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc)) {
+           ts->dig->sha1ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
+           (void) rpmDigestUpdate(ts->dig->sha1ctx, uh, uhc);
+           ts->dig->nbytes += uhc;
+           uh = headerFreeData(uh, uht);
        }
-       if (fddig->hashalgo == PGPHASHALGO_SHA1) {
-           /*@-branchstate@*/
-           if (ts->dig->sha1ctx != NULL)
-               (void) rpmDigestFinal(ts->dig->sha1ctx, NULL, NULL, 0);
-           /*@=branchstate@*/
-           ts->dig->sha1ctx = fddig->hashctx;
-           fddig->hashctx = NULL;
-           continue;
+       /*@=branchstate@*/
+    }  break;
+    case RPMSIGTAG_GPG:
+    case RPMSIGTAG_PGP5:       /* XXX legacy */
+    case RPMSIGTAG_PGP:
+       /* Parse the parameters from the OpenPGP packets that will be needed. */
+       xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug());
+       /*@fallthrough@*/
+    case RPMSIGTAG_MD5:
+       /* Legacy signatures need the compressed payload in the digest too. */
+       ts->dig->nbytes += headerSizeof(h, hmagic);
+       while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
+           ts->dig->nbytes += count;
+       if (count < 0) {
+           rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"),
+                                       fn, Fstrerror(fd));
+           rc = RPMRC_FAIL;
+           goto exit;
+       }
+       ts->dig->nbytes += count;
+
+       /* XXX Steal the digest-in-progress from the file handle. */
+       /*@-type@*/ /* FIX: cast? */
+       for (i = fd->ndigests - 1; i >= 0; i--) {
+           FDDIGEST_t fddig = fd->digests + i;
+           if (fddig->hashctx == NULL)
+               continue;
+           if (fddig->hashalgo == PGPHASHALGO_MD5) {
+               /*@-branchstate@*/
+               if (ts->dig->md5ctx != NULL)
+                   (void) rpmDigestFinal(ts->dig->md5ctx, NULL, NULL, 0);
+               /*@=branchstate@*/
+               ts->dig->md5ctx = fddig->hashctx;
+               fddig->hashctx = NULL;
+               continue;
+           }
+           if (fddig->hashalgo == PGPHASHALGO_SHA1) {
+               /*@-branchstate@*/
+               if (ts->dig->sha1ctx != NULL)
+                   (void) rpmDigestFinal(ts->dig->sha1ctx, NULL, NULL, 0);
+               /*@=branchstate@*/
+               ts->dig->sha1ctx = fddig->hashctx;
+               fddig->hashctx = NULL;
+               continue;
+           }
        }
+       /*@=type@*/
+       break;
     }
-    /*@=type@*/
 
 /** @todo Implement disable/enable/warn/error/anal policy. */
 
     buf[0] = '\0';
     switch (rpmVerifySignature(ts, buf)) {
     case RPMSIG_OK:            /* Signature is OK. */
-       rpmMessage(RPMMESS_VERBOSE, "%s: %s", fn, buf);
+       rpmMessage(RPMMESS_DEBUG, "%s: %s", fn, buf);
        rc = RPMRC_OK;
        break;
     case RPMSIG_UNKNOWN:       /* Signature is unknown. */
@@ -363,7 +416,7 @@ exit:
        /* Convert legacy headers on the fly ... */
        legacyRetrofit(h, l);
        
-       /* Append (and remap) signature tags. */
+       /* Append (and remap) signature tags to the metadata. */
        headerMergeLegacySigs(h, sig);
 
        /* Bump reference count for return. */
index d08b02a..09f0875 100644 (file)
@@ -974,7 +974,9 @@ int rpmcliQuery(rpmTransactionSet ts, QVA_t qva, const char ** argv)
        qva->qva_showPackage = showQueryPackage;
 
     switch (qva->qva_source) {
+#ifdef DYING
     case RPMQV_RPM:
+#endif
     case RPMQV_SPECFILE:
        break;
     default:
index 671b3a4..6bc1032 100644 (file)
@@ -21,6 +21,8 @@
 /*@access FD_t @*/
 /*@access pgpDig @*/
 
+/**
+ */
 static int manageFile(FD_t *fdp, const char **fnp, int flags,
                /*@unused@*/ int rc)
        /*@globals rpmGlobalMacroContext,
@@ -78,6 +80,7 @@ static int manageFile(FD_t *fdp, const char **fnp, int flags,
 }
 
 /**
+ * Copy header+payload, calculating digest(s) on the fly.
  */
 static int copyFile(FD_t *sfdp, const char **sfnp,
                FD_t *tfdp, const char **tfnp)
@@ -158,11 +161,11 @@ static int rpmReSign(/*@unused@*/ rpmTransactionSet ts,
        }
        switch (l->major) {
        case 1:
-           rpmError(RPMERR_BADSIGTYPE, _("%s: Can't sign v1.0 RPM\n"), rpm);
+           rpmError(RPMERR_BADSIGTYPE, _("%s: Can't sign v1 packaging\n"), rpm);
            goto exit;
            /*@notreached@*/ /*@switchbreak@*/ break;
        case 2:
-           rpmError(RPMERR_BADSIGTYPE, _("%s: Can't re-sign v2.0 RPM\n"), rpm);
+           rpmError(RPMERR_BADSIGTYPE, _("%s: Can't re-sign v2 packaging\n"), rpm);
            goto exit;
            /*@notreached@*/ /*@switchbreak@*/ break;
        default:
@@ -202,18 +205,25 @@ static int rpmReSign(/*@unused@*/ rpmTransactionSet ts,
            }
 
            (void) headerRemoveEntry(sig, RPMSIGTAG_SIZE);
-           (void) headerRemoveEntry(sig, RPMSIGTAG_MD5);
+           (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase);
            (void) headerRemoveEntry(sig, RPMSIGTAG_LEMD5_1);
            (void) headerRemoveEntry(sig, RPMSIGTAG_LEMD5_2);
+           (void) headerRemoveEntry(sig, RPMSIGTAG_MD5);
+           (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, qva->passPhrase);
+#ifdef NOTNOW
+           (void) headerRemoveEntry(sig, RPMSIGTAG_SHA1);
+           (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SHA1, qva->passPhrase);
+
            (void) headerRemoveEntry(sig, RPMSIGTAG_PGP5);
            (void) headerRemoveEntry(sig, RPMSIGTAG_PGP);
            (void) headerRemoveEntry(sig, RPMSIGTAG_GPG);
-           (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_SIZE, qva->passPhrase);
-           (void) rpmAddSignature(sig, sigtarget, RPMSIGTAG_MD5, qva->passPhrase);
+#endif
        }
 
-       if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0)
+       if ((sigtype = rpmLookupSignatureType(RPMLOOKUPSIG_QUERY)) > 0) {
+           (void) headerRemoveEntry(sig, sigtype);
            (void) rpmAddSignature(sig, sigtarget, sigtype, qva->passPhrase);
+       }
 
        /* Write the lead/signature of the output rpm */
        strcpy(tmprpm, rpm);
@@ -466,7 +476,6 @@ static int readFile(FD_t fd, int_32 sigtag, const char * fn, pgpDig dig)
        rpmError(RPMERR_FREAD, _("%s: Fread failed: %s\n"), fn, Fstrerror(fd));
        goto exit;
     }
-    dig->nbytes += count;
 
     /*@-type@*/ /* FIX: cast? */
     for (i = fd->ndigests - 1; i >= 0; i--) {
@@ -546,14 +555,20 @@ int rpmVerifySignatures(QVA_t qva, rpmTransactionSet ts, FD_t fd,
        }
 
        /* Grab a hint of what needs doing to avoid duplication. */
-       if (headerIsEntry(sig, RPMSIGTAG_GPG))
+       if (headerIsEntry(sig, RPMSIGTAG_DSA))
+           sigtag = RPMSIGTAG_DSA;
+       else if (headerIsEntry(sig, RPMSIGTAG_GPG))
            sigtag = RPMSIGTAG_GPG;
        else if (headerIsEntry(sig, RPMSIGTAG_PGP))
            sigtag = RPMSIGTAG_PGP;
        else if (headerIsEntry(sig, RPMSIGTAG_MD5))
            sigtag = RPMSIGTAG_MD5;
+#ifdef NOTYET
+       else if (headerIsEntry(sig, RPMSIGTAG_SHA1))
+           sigtag = RPMSIGTAG_SHA1;    /* XXX never happens */
+#endif
        else
-           sigtag = 0; /* XXX never happens */
+           sigtag = 0;                 /* XXX never happens */
 
        ts->dig = pgpNewDig();
 
@@ -589,6 +604,7 @@ if (rpmIsDebug())
 fprintf(stderr, "========================= Package RSA Signature\n");
                xx = pgpPrtPkts(ts->sig, ts->siglen, ts->dig, rpmIsDebug());
                /*@switchbreak@*/ break;
+           case RPMSIGTAG_DSA:
            case RPMSIGTAG_GPG:
                if (!(qva->qva_flags & VERIFY_SIGNATURE)) 
                     continue;
@@ -603,11 +619,17 @@ fprintf(stderr, "========================= Package DSA Signature\n");
                     continue;
                /*
                 * Don't bother with md5 if pgp, as RSA/MD5 is more reliable
-                * than the legacy -- now unsupported -- legacy md5 breakage.
+                * than the -- now unsupported -- legacy md5 breakage.
                 */
                if (sigtag == RPMSIGTAG_PGP)
                    continue;
                /*@switchbreak@*/ break;
+           case RPMSIGTAG_SHA1:
+#ifdef NOTYET
+               if (!(qva->qva_flags & VERIFY_DIGEST)) 
+                    continue;
+               /*@switchbreak@*/ break;
+#endif
            default:
                continue;
                /*@notreached@*/ /*@switchbreak@*/ break;
@@ -662,6 +684,7 @@ fprintf(stderr, "========================= Package DSA Signature\n");
                            /*@innerbreak@*/ break;
                        }
                        /*@switchbreak@*/ break;
+                   case RPMSIGTAG_DSA:
                    case RPMSIGTAG_GPG:
                        /* Do not consider this a failure */
                        switch (res3) {
@@ -703,6 +726,7 @@ fprintf(stderr, "========================= Package DSA Signature\n");
                    case RPMSIGTAG_PGP:
                        b = stpcpy(b, "pgp ");
                        /*@switchbreak@*/ break;
+                   case RPMSIGTAG_DSA:
                    case RPMSIGTAG_GPG:
                        b = stpcpy(b, "gpg ");
                        /*@switchbreak@*/ break;
index 4b34fbb..1f73109 100644 (file)
@@ -228,6 +228,7 @@ typedef enum rpmTag_e {
 /*@=enummemuse@*/
     RPMTAG_SHA1HEADER          = RPMTAG_SIG_BASE+9,
     RPMTAG_PUBKEYS             = RPMTAG_SIG_BASE+10,
+    RPMTAG_DSAHEADER           = RPMTAG_SIG_BASE+11,
 
     RPMTAG_NAME                = 1000,
     RPMTAG_VERSION             = 1001,
@@ -773,9 +774,9 @@ typedef /*@abstract@*/ struct _rpmdbMatchIterator * rpmdbMatchIterator;
        /*@modifies mi, fileSystem @*/;
 
 /** \ingroup rpmdb
- * Return join key for current position of rpm database iterator.
+ * Return header join key for current position of rpm database iterator.
  * @param mi           rpm database iterator
- * @return             current join key
+ * @return             current header join key
  */
 unsigned int rpmdbGetIteratorOffset(/*@null@*/ rpmdbMatchIterator mi)
        /*@*/;
@@ -1780,12 +1781,16 @@ typedef enum rpmEraseInterfaceFlags_e {
 enum rpmtagSignature {
     RPMSIGTAG_SIZE     = 1000, /*!< Header+Payload size in bytes. */
 /* the md5 sum was broken *twice* on big endian machines */
-    RPMSIGTAG_LEMD5_1  = 1001, /*!< Broken MD5, take 1 */
+    RPMSIGTAG_LEMD5_1  = 1001, /*!< Broken MD5, take 1 @deprecated legacy. */
     RPMSIGTAG_PGP      = 1002, /*!< PGP 2.6.3 signature. */
-    RPMSIGTAG_LEMD5_2  = 1003, /*!< Broken MD5, take 2 */
+    RPMSIGTAG_LEMD5_2  = 1003, /*!< Broken MD5, take 2 @deprecated legacy. */
     RPMSIGTAG_MD5      = 1004, /*!< MD5 signature. */
     RPMSIGTAG_GPG      = 1005, /*!< GnuPG signature. */
     RPMSIGTAG_PGP5     = 1006, /*!< PGP5 signature @deprecated legacy. */
+    RPMSIGTAG_PAYLOADSIZE = 1007,
+                               /*!< uncompressed payload size in bytes. */
+    RPMSIGTAG_SHA1     = RPMTAG_SHA1HEADER,    /*!< sha1 header digest. */
+    RPMSIGTAG_DSA      = RPMTAG_DSAHEADER,     /*!< DSA header signature. */
 };
 
 /**
index 40ed66c..f9a81b2 100644 (file)
@@ -7,6 +7,7 @@
 #include "rpmio_internal.h"
 #include <rpmlib.h>
 #include <rpmmacro.h>  /* XXX for rpmGetPath() */
+#include "rpmdb.h"
 
 #include "depends.h"
 #include "misc.h"      /* XXX for dosetenv() and makeTempFile() */
@@ -483,6 +484,10 @@ int rpmAddSignature(Header h, const char * file, int_32 sigTag,
        if (ret == 0)
            (void) headerAddEntry(h, sigTag, RPM_BIN_TYPE, sig, size);
        break;
+    case RPMSIGTAG_DSA:                /* XXX UNIMPLEMENTED */
+       break;
+    case RPMSIGTAG_SHA1:       /* XXX UNIMPLEMENTED */
+       break;
     }
 
     return ret;
@@ -523,6 +528,7 @@ static int checkPassPhrase(const char * passPhrase, const int sigTag)
        (void) dup2(passPhrasePipe[0], 3);
 
        switch (sigTag) {
+       case RPMSIGTAG_DSA:
        case RPMSIGTAG_GPG:
        {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
 
@@ -597,6 +603,7 @@ char * rpmGetPassPhrase(const char * prompt, const int sigTag)
     int aok;
 
     switch (sigTag) {
+    case RPMSIGTAG_DSA:
     case RPMSIGTAG_GPG:
       { const char *name = rpmExpand("%{?_gpg_name}", NULL);
        aok = (name && *name != '\0');
@@ -662,21 +669,31 @@ verifySizeSignature(const rpmTransactionSet ts, /*@out@*/ char * t)
     *t = '\0';
     t = stpcpy(t, _("Header+Payload size: "));
 
-/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */
+    if (ts->sig == NULL || ts->dig == NULL) {
+       res = RPMSIG_NOKEY;
+       t = stpcpy(t, rpmSigString(res));
+       goto exit;
+    }
+
+/*@=nullpass =nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */
     memcpy(&size, ts->sig, sizeof(size));
 
     /*@-type@*/
     /*@-nullderef@*/ /* FIX: ts->dig can be NULL */
     if (size != ts->dig->nbytes) {
        res = RPMSIG_BAD;
-       sprintf(t, "BAD Expected(%d) != (%d)\n", size, ts->dig->nbytes);
+       t = stpcpy(t, rpmSigString(res));
+       sprintf(t, " Expected(%d) != (%d)\n", size, ts->dig->nbytes);
     } else {
        res = RPMSIG_OK;
-       sprintf(t, "OK (%d)\n", ts->dig->nbytes);
+       t = stpcpy(t, rpmSigString(res));
+       sprintf(t, " (%d)", ts->dig->nbytes);
     }
     /*@=type@*/
 /*@=nullpass =nullderef@*/
 
+exit:
+    t = stpcpy(t, "\n");
     return res;
 }
 
@@ -691,7 +708,13 @@ verifyMD5Signature(const rpmTransactionSet ts, /*@out@*/ char * t)
     *t = '\0';
     t = stpcpy(t, _("MD5 digest: "));
 
-/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */
+    if (ts->sig == NULL || ts->dig == NULL) {
+       res = RPMSIG_NOKEY;
+       t = stpcpy(t, rpmSigString(res));
+       goto exit;
+    }
+
+/*@=nullpass =nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */
     /*@-type@*/
     (void) rpmDigestFinal(rpmDigestDup(ts->dig->md5ctx),
                (void **)&md5sum, &md5len, 0);
@@ -699,21 +722,172 @@ verifyMD5Signature(const rpmTransactionSet ts, /*@out@*/ char * t)
 
     if (md5len != ts->siglen || memcmp(md5sum, ts->sig, md5len)) {
        res = RPMSIG_BAD;
-       t = stpcpy(t, "BAD Expected(");
+       t = stpcpy(t, rpmSigString(res));
+       t = stpcpy(t, " Expected(");
        (void) pgpHexCvt(t, ts->sig, ts->siglen);
        t += strlen(t);
        t = stpcpy(t, ") != (");
     } else {
        res = RPMSIG_OK;
-       t = stpcpy(t, "OK (");
+       t = stpcpy(t, rpmSigString(res));
+       t = stpcpy(t, " (");
     }
 /*@=nullpass =nullderef@*/
     (void) pgpHexCvt(t, md5sum, md5len);
     t += strlen(t);
-    t = stpcpy(t, ")\n");
+    t = stpcpy(t, ")");
 
+exit:
     md5sum = _free(md5sum);
+    t = stpcpy(t, "\n");
+    return res;
+}
+
+static rpmVerifySignatureReturn
+verifySHA1Signature(const rpmTransactionSet ts, /*@out@*/ char * t)
+       /*@modifies *t @*/
+{
+    rpmVerifySignatureReturn res;
+    const char * sha1 = NULL;
+
+    *t = '\0';
+    t = stpcpy(t, _("SHA1 header digest: "));
+
+    if (ts->sig == NULL || ts->dig == NULL) {
+       res = RPMSIG_NOKEY;
+       t = stpcpy(t, rpmSigString(res));
+       goto exit;
+    }
+
+    /*@-type@*/
+    (void) rpmDigestFinal(rpmDigestDup(ts->dig->sha1ctx),
+               (void **)&sha1, NULL, 1);
+    /*@=type@*/
+
+    if (sha1 == NULL || strlen(sha1) != strlen(ts->sig)) {
+       res = RPMSIG_BAD;
+       t = stpcpy(t, rpmSigString(res));
+       t = stpcpy(t, " Expected(");
+       t = stpcpy(t, ts->sig);
+       t = stpcpy(t, ") != (");
+    } else {
+       res = RPMSIG_OK;
+       t = stpcpy(t, rpmSigString(res));
+       t = stpcpy(t, " (");
+    }
+    if (sha1)
+       t = stpcpy(t, sha1);
+    t = stpcpy(t, ")");
+
+exit:
+    sha1 = _free(sha1);
+    t = stpcpy(t, "\n");
+    return res;
+}
+
+/**
+ * Retrieve pubkey from rpm database.
+ * @param ts           rpm transaction
+ * @return             RPMSIG_OK on success, RPMSIG_NOKEY if not found
+ */
+static rpmVerifySignatureReturn
+rpmtsFindPubkey(rpmTransactionSet ts)
+       /*@modifies ts */
+{
+    struct pgpDigParams_s * sigp = NULL;
+    rpmVerifySignatureReturn res;
+    /*@unchecked@*/ /*@only@*/ static const byte * pkpkt = NULL;
+    /*@unchecked@*/ static size_t pkpktlen = 0;
+    /*@unchecked@*/ static byte pksignid[8];
+    int xx;
+
+    if (ts->sig == NULL || ts->dig == NULL) {
+       res = RPMSIG_NOKEY;
+       goto exit;
+    }
+    sigp = &ts->dig->signature;
+
+    /*@-globs -internalglobs -mods -modfilesys@*/
+    if (pkpkt == NULL || memcmp(sigp->signid, pksignid, sizeof(pksignid))) {
+       int ix = -1;
+       rpmdbMatchIterator mi;
+       Header h;
+
+       pkpkt = _free(pkpkt);
+       pkpktlen = 0;
+       memset(pksignid, 0, sizeof(pksignid));
+
+       (void) rpmtsOpenDB(ts, ts->dbmode);
+
+       mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
+       while ((h = rpmdbNextIterator(mi)) != NULL) {
+           const char ** pubkeys;
+           int_32 pt, pc;
+
+           if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
+               continue;
+           ix = rpmdbGetIteratorFileNum(mi);
+           if (ix >= pc
+           || b64decode(pubkeys[ix], (void **) &pkpkt, &pkpktlen))
+               ix = -1;
+           pubkeys = headerFreeData(pubkeys, pt);
+           break;
+       }
+       mi = rpmdbFreeIterator(mi);
+
+       if (ix < 0 || pkpkt == NULL) {
+           res = RPMSIG_NOKEY;
+           goto exit;
+       }
+
+       /* Make sure the pkt can be parsed, print info if debugging. */
+       if (pgpPrtPkts(pkpkt, pkpktlen, NULL, 0)) {
+           res = RPMSIG_NOKEY;
+           goto exit;
+       }
+
+       /* XXX Verify the pubkey signature. */
+
+       /* Packet looks good, save the signer id. */
+       memcpy(pksignid, sigp->signid, sizeof(pksignid));
+    }
+
+#ifdef NOTNOW
+    {
+       if (pkpkt == NULL) {
+           const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL);
+           if (pgpReadPkts(pkfn, &pkpkt, &pkpktlen) != PGPARMOR_PUBKEY) {
+               pkfn = _free(pkfn);
+               res = RPMSIG_NOKEY;
+               goto exit;
+           }
+           pkfn = _free(pkfn);
+       }
+    }
+#endif
+
+    rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %s\n",
+       (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
+       (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
+       pgpHexStr(sigp->signid, sizeof(sigp->signid)));
+
+    /* Retrieve parameters from pubkey packet(s). */
+    xx = pgpPrtPkts(pkpkt, pkpktlen, ts->dig, 0);
+    /*@=globs =internalglobs =mods =modfilesys@*/
+
+    /* Make sure we have the correct public key. */
+    if (ts->dig->signature.pubkey_algo == ts->dig->pubkey.pubkey_algo
+#ifdef NOTYET
+     && ts->dig->signature.hash_algo == ts->dig->pubkey.hash_algo
+#endif
+     &&        !memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
+       res = RPMSIG_OK;
+    else
+       res = RPMSIG_NOKEY;
+
+    /* XXX Verify the signature signature. */
 
+exit:
     return res;
 }
 
@@ -721,22 +895,33 @@ static rpmVerifySignatureReturn
 verifyPGPSignature(rpmTransactionSet ts, /*@out@*/ char * t)
        /*@modifies ts, *t */
 {
-/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */
+    struct pgpDigParams_s * sigp = NULL;
     rpmVerifySignatureReturn res;
-    struct pgpDigParams_s * digp = &ts->dig->signature;
-    /*@unchecked@*/ static const byte * pgppk = NULL;
-    /*@unchecked@*/ static size_t pgppklen = 0;
     int xx;
 
     *t = '\0';
     t = stpcpy(t, _("V3 RSA/MD5 signature: "));
 
+    if (ts->sig == NULL || ts->dig == NULL) {
+       res = RPMSIG_NOKEY;
+       goto exit;
+    }
+    sigp = &ts->dig->signature;
+
     /* XXX sanity check on ts->sigtag and signature agreement. */
+    if (!(ts->sigtag == RPMSIGTAG_PGP
+       && sigp->pubkey_algo == PGPPUBKEYALGO_RSA
+       && sigp->hash_algo == PGPHASHALGO_MD5))
+    {
+       res = RPMSIG_NOKEY;
+       goto exit;
+    }
 
     /*@-type@*/ /* FIX: cast? */
     {  DIGEST_CTX ctx = rpmDigestDup(ts->dig->md5ctx);
 
-       xx = rpmDigestUpdate(ctx, digp->hash, digp->hashlen);
+       if (sigp->hash != NULL)
+           xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
        xx = rpmDigestFinal(ctx, (void **)&ts->dig->md5, &ts->dig->md5len, 1);
 
        /* XXX compare leading 16 bits of digest for quick check. */
@@ -763,46 +948,25 @@ verifyPGPSignature(rpmTransactionSet ts, /*@out@*/ char * t)
        hexstr = _free(hexstr);
     }
 
-    /* XXX retrieve by keyid from signature. */
-
-    /*@-globs -internalglobs -mods -modfilesys@*/
-    if (pgppk == NULL) {
-       const char * pkfn = rpmExpand("%{_pgp_pubkey}", NULL);
-       if (pgpReadPkts(pkfn, &pgppk, &pgppklen) != PGPARMOR_PUBKEY) {
-           pkfn = _free(pkfn);
-           res = RPMSIG_NOKEY;
-           goto exit;
-       }
-       rpmMessage(RPMMESS_DEBUG,
-               "========== PGP RSA/MD5 pubkey %s\n", pkfn);
-       xx = pgpPrtPkts(pgppk, pgppklen, NULL, rpmIsDebug());
-       pkfn = _free(pkfn);
-    }
-
-    /* Retrieve parameters from pubkey packet(s). */
-    xx = pgpPrtPkts(pgppk, pgppklen, ts->dig, 0);
-    /*@=globs =internalglobs =mods =modfilesys@*/
-
-    /* Make sure we have the correct public key. */
-    if (ts->dig->signature.pubkey_algo != ts->dig->pubkey.pubkey_algo
-     || memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
-    {
-       res = RPMSIG_NOKEY;
+    /* Retrieve the matching public key. */
+    res = rpmtsFindPubkey(ts);
+    if (res != RPMSIG_OK)
        goto exit;
-    }
 
     /*@-type@*/
-    if (!rsavrfy(&ts->dig->rsa_pk, &ts->dig->rsahm, &ts->dig->c))
-       res = RPMSIG_BAD;
-    else
+    if (rsavrfy(&ts->dig->rsa_pk, &ts->dig->rsahm, &ts->dig->c))
        res = RPMSIG_OK;
+    else
+       res = RPMSIG_BAD;
     /*@=type@*/
-/*@=nullpass =nullderef@*/
 
 exit:
-    t = stpcpy( stpcpy(t, rpmSigString(res)), ", key ID ");
-    (void) pgpHexCvt(t, digp->signid+4, sizeof(digp->signid)-4);
-    t += strlen(t);
+    t = stpcpy(t, rpmSigString(res));
+    if (sigp != NULL) {
+       t = stpcpy(t, ", key ID ");
+       (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
+       t += strlen(t);
+    }
     t = stpcpy(t, "\n");
     return res;
 }
@@ -811,71 +975,61 @@ static rpmVerifySignatureReturn
 verifyGPGSignature(rpmTransactionSet ts, /*@out@*/ char * t)
        /*@modifies ts, *t @*/
 {
-/*@-nullpass -nullderef@*/ /* FIX: ts->{sig,dig} can be NULL */
+    struct pgpDigParams_s * sigp = NULL;
     rpmVerifySignatureReturn res;
-    struct pgpDigParams_s * digp = &ts->dig->signature;
-    /*@unchecked@*/ static const byte * gpgpk = NULL;
-    /*@unchecked@*/ static size_t gpgpklen = 0;
     int xx;
 
     *t = '\0';
     t = stpcpy(t, _("V3 DSA signature: "));
 
+    if (ts->sig == NULL || ts->dig == NULL) {
+       res = RPMSIG_NOKEY;
+       goto exit;
+    }
+    sigp = &ts->dig->signature;
+
     /* XXX sanity check on ts->sigtag and signature agreement. */
+    if (!((ts->sigtag == RPMSIGTAG_GPG || ts->sigtag == RPMSIGTAG_DSA)
+       && sigp->pubkey_algo == PGPPUBKEYALGO_DSA
+       && sigp->hash_algo == PGPHASHALGO_SHA1))
+    {
+       res = RPMSIG_NOKEY;
+       goto exit;
+    }
 
     /*@-type@*/ /* FIX: cast? */
     {  DIGEST_CTX ctx = rpmDigestDup(ts->dig->sha1ctx);
 
-       xx = rpmDigestUpdate(ctx, digp->hash, digp->hashlen);
+       if (sigp->hash != NULL)
+           xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
        xx = rpmDigestFinal(ctx, (void **)&ts->dig->sha1, &ts->dig->sha1len, 1);
 
+       /* XXX compare leading 16 bits of digest for quick check. */
+
        mp32nzero(&ts->dig->hm);        mp32nsethex(&ts->dig->hm, ts->dig->sha1);
     }
     /*@=type@*/
 
-    /* XXX retrieve by keyid from signature. */
-
-    /*@-globs -internalglobs -mods -modfilesys@*/
-    if (gpgpk == NULL) {
-       const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL);
-       int printing = 0;       /* XXX was rpmIsDebug() */
-
-       if (pgpReadPkts(pkfn, &gpgpk, &gpgpklen) != PGPARMOR_PUBKEY) {
-           pkfn = _free(pkfn);
-           res = RPMSIG_NOKEY;
-           goto exit;
-       }
-       rpmMessage(RPMMESS_DEBUG,
-               "========== GPG DSA pubkey %s\n", pkfn);
-       xx = pgpPrtPkts(gpgpk, gpgpklen, NULL, printing);
-       pkfn = _free(pkfn);
-    }
-
-    /* Retrieve parameters from pubkey packet(s). */
-    xx = pgpPrtPkts(gpgpk, gpgpklen, ts->dig, 0);
-    /*@=globs =internalglobs =mods =modfilesys@*/
-
-    /* Make sure we have the correct public key. */
-    if (ts->dig->signature.pubkey_algo != ts->dig->pubkey.pubkey_algo
-     || memcmp(ts->dig->signature.signid, ts->dig->pubkey.signid, 8))
-    {
-       res = RPMSIG_NOKEY;
+    /* Retrieve the matching public key. */
+    res = rpmtsFindPubkey(ts);
+    if (res != RPMSIG_OK)
        goto exit;
-    }
 
     /*@-type@*/
-    if (!dsavrfy(&ts->dig->p, &ts->dig->q, &ts->dig->g,
+    if (dsavrfy(&ts->dig->p, &ts->dig->q, &ts->dig->g,
                &ts->dig->hm, &ts->dig->y, &ts->dig->r, &ts->dig->s))
-       res = RPMSIG_BAD;
-    else
        res = RPMSIG_OK;
+    else
+       res = RPMSIG_BAD;
     /*@=type@*/
-/*@=nullpass =nullderef@*/
 
 exit:
-    t = stpcpy( stpcpy(t, rpmSigString(res)), ", key ID ");
-    (void) pgpHexCvt(t, digp->signid+4, sizeof(digp->signid)-4);
-    t += strlen(t);
+    t = stpcpy(t, rpmSigString(res));
+    if (sigp != NULL) {
+       t = stpcpy(t, ", key ID ");
+       (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
+       t += strlen(t);
+    }
     t = stpcpy(t, "\n");
     return res;
 }
@@ -897,10 +1051,14 @@ rpmVerifySignature(const rpmTransactionSet ts, char * result)
     case RPMSIGTAG_MD5:
        res = verifyMD5Signature(ts, result);
        break;
+    case RPMSIGTAG_SHA1:
+       res = verifySHA1Signature(ts, result);
+       break;
     case RPMSIGTAG_PGP5:       /* XXX legacy */
     case RPMSIGTAG_PGP:
        res = verifyPGPSignature(ts, result);
        break;
+    case RPMSIGTAG_DSA:
     case RPMSIGTAG_GPG:
        res = verifyGPGSignature(ts, result);
        break;
index 13a30e3..c3f544b 100644 (file)
@@ -572,10 +572,12 @@ int rpmcliVerify(rpmTransactionSet ts, QVA_t qva, const char ** argv)
         qva->qva_showPackage = showVerifyPackage;
 
     switch (qva->qva_source) {
+#ifdef DYING
     case RPMQV_RPM:
        if (!(qva->qva_flags & VERIFY_DEPS))
            break;
        /*@fallthrough@*/
+#endif
     default:
        if (rpmtsOpenDB(ts, O_RDONLY))
            return 1;   /* XXX W2DO? */
index df22b86..a4d0484 100644 (file)
--- a/rpm.spec
+++ b/rpm.spec
@@ -2,7 +2,7 @@
 %define        with_python_version     2.2%{nil}
 %define with_perl_subpackage   1
 %define        with_bzip2              1%{nil}
-%define        with_apidocs            1%{nil}
+%define        with_apidocs            0%{nil}
 %define with_internal_db       1%{nil}
 %define strip_binaries         1
 
@@ -479,7 +479,7 @@ fi
 %files devel
 %defattr(-,root,root)
 %if %{with_apidocs}
-%doc apidocs
+%doc 
 %endif
 %{__prefix}/include/rpm
 %{__prefix}/lib/librpm.a
@@ -647,3 +647,11 @@ fi
 - add cpanflute2, another perl.req fiddle.
 - make peace with gcc-3.1, remove compiler cruft.
 - make peace with automake et al in 8.0, ugh.
+- add payload uncompressed size to signature to avoid rewriting header.
+- drill header sha1 into signature parallel to header+payload md5.
+- mandatory "most effective" signature check on query/verify/install.
+- don't bother adding empty filemd's to index.
+- add Pubkey index, using signer id as binary key.
+- display pubkeys in hex when debugging db access.
+- retrieve pubkey(s) from rpmdb, not from detached signature file.
+- reapply Berkeley DB patch #4491.
index b1898f2..f89f7ab 100644 (file)
@@ -647,3 +647,11 @@ fi
 - add cpanflute2, another perl.req fiddle.
 - make peace with gcc-3.1, remove compiler cruft.
 - make peace with automake et al in 8.0, ugh.
+- add payload uncompressed size to signature to avoid rewriting header.
+- drill header sha1 into signature parallel to header+payload md5.
+- mandatory "most effective" signature check on query/verify/install.
+- don't bother adding empty filemd's to index.
+- add Pubkey index, using signer id as binary key.
+- display pubkeys in hex when debugging db access.
+- retrieve pubkey(s) from rpmdb, not from detached signature file.
+- reapply Berkeley DB patch #4491.
index 339804b..b879142 100644 (file)
@@ -33,6 +33,7 @@ extern void regfree (/*@only@*/ regex_t *preg)
 #endif
 
 #include <rpmcli.h>
+#include <rpmpgp.h>
 
 #include "rpmdb.h"
 #include "fprint.h"
@@ -63,6 +64,38 @@ static int _db_filter_dups = 0;
 int dbiTagsMax = 0;
 
 /**
+ * Convert hex to binary nibble.
+ * @param c            hex character
+ * @return             binary nibble
+ */
+static inline unsigned char nibble(char c)
+       /*@*/
+{
+    if (c >= '0' && c <= '9')
+       return (c - '0');
+    if (c >= 'A' && c <= 'F')
+       return (c - 'A') + 10;
+    if (c >= 'a' && c <= 'f')
+       return (c - 'a') + 10;
+    return 0;
+}
+
+/**
+ * Check key for printable characters.
+ * @param ptr          key value pointer
+ * @param len          key value length
+ * @return             1 if only ASCII, 0 otherwise.
+ */
+static int printable(const void * ptr, size_t len)     /*@*/
+{
+    const char * s = ptr;
+    int i;
+    for (i = 0; i < len; i++, s++)
+       if (!(*s >= ' ' && *s <= '~')) return 0;
+    return 1;
+}
+
+/**
  * Return dbi index used for rpm tag.
  * @param rpmtag       rpm header tag
  * @return             dbi index, -1 on error
@@ -209,15 +242,6 @@ fprintf(stderr, "--- RMW %s\n", tagName(dbi->dbi_rpmtag));
     return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
 }
 
-static int printable(const void * ptr, size_t len)     /*@*/
-{
-    const char * s = ptr;
-    int i;
-    for (i = 0; i < len; i++, s++)
-       if (!(*s >= ' ' && *s <= '~')) return 0;
-    return 1;
-}
-
 INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor,
        const void * keyp, size_t keylen, unsigned int flags)
 {
@@ -257,13 +281,24 @@ if (_debug < 0 || dbi->dbi_debug) {
  char keyval[64];
  keyval[0] = '\0';
  if (keypp && *keypp && keylenp) {
-  if (*keylenp <= sizeof(int) && !printable(*keypp, *keylenp)) {
+  if (printable(*keypp, *keylenp)) {
+    kvp = *keypp;
+  } else if (*keylenp <= sizeof(int)) {
     int keyint = 0;
     memcpy(&keyint, *keypp, sizeof(keyint));
     sprintf(keyval, "#%d", keyint);
     kvp = keyval;
   } else {
-    kvp = *keypp;
+    static const char hex[] = "0123456789abcdef";
+    const byte * s = *keypp;
+    char * t = keyval;
+    int i;
+    for (i = 0; i < *keylenp && t < (keyval+sizeof(keyval)-2); i++) {
+      *t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ];
+      *t++ = hex[ (unsigned)((*s++   ) & 0x0f) ];
+    }
+    *t = '\0';
+    kvp = keyval;
   }
  } else
    kvp = keyval;
@@ -298,13 +333,24 @@ if (_debug < 0 || dbi->dbi_debug) {
  char keyval[64];
  keyval[0] = '\0';
  if (keyp) {
-  if (keylen == sizeof(int) && !printable(keyp, keylen)) {
+  if (printable(keyp, keylen)) {
+    kvp = keyp;
+  } else if (keylen <= sizeof(int)) {
     int keyint = 0;
     memcpy(&keyint, keyp, sizeof(keyint));
     sprintf(keyval, "#%d", keyint);
     kvp = keyval;
   } else {
-    kvp = keyp;
+    static const char hex[] = "0123456789abcdef";
+    const byte * s = keyp;
+    char * t = keyval;
+    int i;
+    for (i = 0; i < keylen && t < (keyval+sizeof(keyval)-2); i++) {
+      *t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ];
+      *t++ = hex[ (unsigned)((*s++   ) & 0x0f) ];
+    }
+    *t = '\0';
+    kvp = keyval;
   }
  } else
    kvp = keyval;
@@ -2457,7 +2503,7 @@ int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum)
            int rpmcnt = 0;
            int rpmtag;
            int xx;
-           int i;
+           int i, j;
 
            dbi = NULL;
            rpmtag = dbiTags[dbix];
@@ -2506,6 +2552,17 @@ int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum)
                const void * valp;
                size_t vallen;
                int stringvalued;
+               byte bin[32];
+
+               switch (dbi->dbi_rpmtag) {
+               case RPMTAG_FILEMD5S:
+                   /* Filter out empty MD5 strings. */
+                   if (!(rpmvals[i] && *rpmvals[i] != '\0'))
+                       /*@innercontinue@*/ continue;
+                   /*@switchbreak@*/ break;
+               default:
+                   /*@switchbreak@*/ break;
+               }
 
                /* Identify value pointer and length. */
                stringvalued = 0;
@@ -2533,6 +2590,36 @@ int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum)
                    rpmcnt = 1;         /* XXX break out of loop. */
                    /*@fallthrough@*/
                case RPM_STRING_ARRAY_TYPE:
+                   /* Convert from hex to binary. */
+                   if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
+                       const char * s;
+                       byte * t;
+
+                       s = rpmvals[i];
+                       t = bin;
+                       for (j = 0; j < 16; j++, t++, s += 2)
+                           *t = (nibble(s[0]) << 4) | nibble(s[1]);
+                       valp = bin;
+                       vallen = 16;
+                       /*@switchbreak@*/ break;
+                   }
+                   /* Extract the pubkey id from the base64 blob. */
+                   if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
+                       pgpDig dig = pgpNewDig();
+                       const byte * pkt;
+                       ssize_t pktlen;
+
+                       if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
+                           continue;
+                       (void) pgpPrtPkts(pkt, pktlen, dig, 0);
+                       memcpy(bin, dig->pubkey.signid, 8);
+                       pkt = _free(pkt);
+                       dig = _free(dig);
+                       valp = bin;
+                       vallen = 8;
+                       /*@switchbreak@*/ break;
+                   }
+                   /*@fallthrough@*/
                default:
                    vallen = strlen(rpmvals[i]);
                    valp = rpmvals[i];
@@ -2812,17 +2899,25 @@ int rpmdbAdd(rpmdb db, int iid, Header h)
                const void * valp;
                size_t vallen;
                int stringvalued;
+               byte bin[32];
 
                /*
                 * Include the tagNum in all indices. rpm-3.0.4 and earlier
                 * included the tagNum only for files.
                 */
+               rec->tagNum = i;
                switch (dbi->dbi_rpmtag) {
+               case RPMTAG_PUBKEYS:
+                   /*@switchbreak@*/ break;
+               case RPMTAG_FILEMD5S:
+                   /* Filter out empty MD5 strings. */
+                   if (!(rpmvals[i] && *rpmvals[i] != '\0'))
+                       /*@innercontinue@*/ continue;
+                   /*@switchbreak@*/ break;
                case RPMTAG_REQUIRENAME:
                    /* Filter out install prerequisites. */
                    if (requireFlags && isInstallPreReq(requireFlags[i]))
                        /*@innercontinue@*/ continue;
-                   rec->tagNum = i;
                    /*@switchbreak@*/ break;
                case RPMTAG_TRIGGERNAME:
                    if (i) {    /* don't add duplicates */
@@ -2833,10 +2928,8 @@ int rpmdbAdd(rpmdb db, int iid, Header h)
                        if (j < i)
                            /*@innercontinue@*/ continue;
                    }
-                   rec->tagNum = i;
                    /*@switchbreak@*/ break;
                default:
-                   rec->tagNum = i;
                    /*@switchbreak@*/ break;
                }
 
@@ -2866,6 +2959,36 @@ int rpmdbAdd(rpmdb db, int iid, Header h)
                    rpmcnt = 1;         /* XXX break out of loop. */
                    /*@fallthrough@*/
                case RPM_STRING_ARRAY_TYPE:
+                   /* Convert from hex to binary. */
+                   if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
+                       const char * s;
+                       byte * t;
+
+                       s = rpmvals[i];
+                       t = bin;
+                       for (j = 0; j < 16; j++, t++, s += 2)
+                           *t = (nibble(s[0]) << 4) | nibble(s[1]);
+                       valp = bin;
+                       vallen = 16;
+                       /*@switchbreak@*/ break;
+                   }
+                   /* Extract the pubkey id from the base64 blob. */
+                   if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
+                       pgpDig dig = pgpNewDig();
+                       const byte * pkt;
+                       ssize_t pktlen;
+
+                       if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
+                           continue;
+                       (void) pgpPrtPkts(pkt, pktlen, dig, 0);
+                       memcpy(bin, dig->pubkey.signid, 8);
+                       pkt = _free(pkt);
+                       dig = _free(dig);
+                       valp = bin;
+                       vallen = 8;
+                       /*@switchbreak@*/ break;
+                   }
+                   /*@fallthrough@*/
                default:
                    valp = rpmvals[i];
                    vallen = strlen(rpmvals[i]);
index 4dc5150..c0fd4dd 100644 (file)
@@ -519,7 +519,6 @@ char * db1basename(int rpmtag)
 
 /** \ingroup rpmdb
  */
-/*@unused@*/
 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi)
        /*@*/;
 
index 8c645ca..28eb403 100644 (file)
@@ -507,11 +507,11 @@ void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo,
     if (i < 0) {
        if (datap) *datap = NULL;
        if (lenp) *lenp = 0;
-       return;
-    } else if (i == imax)
-       fd->ndigests = imax - 1;
-    else
-       fd->ndigests = imax;
+    }
+
+    fd->ndigests = imax;
+    if (i < imax)
+       fd->ndigests++;         /* convert index to count */
 }
 
 /*@-shadow@*/