BSD 4_4 release
[unix-history] / usr / src / lib / libc / db / hash / hash.c
index 69881da..8344fae 100644 (file)
@@ -1,49 +1,77 @@
 /*-
 /*-
- * Copyright (c) 1990 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Margo Seltzer.
  *
  *
  * This code is derived from software contributed to Berkeley by
  * Margo Seltzer.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)hash.c     5.24 (Berkeley) %G%";
+static char sccsid[] = "@(#)hash.c     8.1 (Berkeley) 7/19/93";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 
-#include <fcntl.h>
 #include <errno.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 #ifdef DEBUG
 #include <assert.h>
 #endif
 #ifdef DEBUG
 #include <assert.h>
 #endif
+
 #include <db.h>
 #include <db.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
 #include "hash.h"
 #include "page.h"
 #include "extern.h"
 
 #include "hash.h"
 #include "page.h"
 #include "extern.h"
 
-static int   alloc_segs __P((int));
-static int   flush_meta __P((void));
-static int   hash_access __P((ACTION, DBT *, DBT *));
+static int   alloc_segs __P((HTAB *, int));
+static int   flush_meta __P((HTAB *));
+static int   hash_access __P((HTAB *, ACTION, DBT *, DBT *));
 static int   hash_close __P((DB *));
 static int   hash_delete __P((const DB *, const DBT *, u_int));
 static int   hash_close __P((DB *));
 static int   hash_delete __P((const DB *, const DBT *, u_int));
+static int   hash_fd __P((const DB *));
 static int   hash_get __P((const DB *, const DBT *, DBT *, u_int));
 static int   hash_get __P((const DB *, const DBT *, DBT *, u_int));
-static int   hash_put __P((const DB *, const DBT *, const DBT *, u_int));
+static int   hash_put __P((const DB *, DBT *, const DBT *, u_int));
 static void *hash_realloc __P((SEGMENT **, int, int));
 static int   hash_seq __P((const DB *, DBT *, DBT *, u_int));
 static void *hash_realloc __P((SEGMENT **, int, int));
 static int   hash_seq __P((const DB *, DBT *, DBT *, u_int));
-static int   hash_sync __P((const DB *));
-static int   hdestroy __P((void));
-static HTAB *init_hash __P((HASHINFO *));
-static int   init_htab __P((int));
+static int   hash_sync __P((const DB *, u_int));
+static int   hdestroy __P((HTAB *));
+static HTAB *init_hash __P((HTAB *, const char *, HASHINFO *));
+static int   init_htab __P((HTAB *, int));
 #if BYTE_ORDER == LITTLE_ENDIAN
 #if BYTE_ORDER == LITTLE_ENDIAN
-static void  swap_header __P((void));
+static void  swap_header __P((HTAB *));
 static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
 #endif
 
 static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
 #endif
 
@@ -57,9 +85,6 @@ static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
 #define        ERROR   (-1)
 #define        ABNORMAL (1)
 
 #define        ERROR   (-1)
 #define        ABNORMAL (1)
 
-/* Local data */
-HTAB *hashp = NULL;
-
 #ifdef HASH_STATISTICS
 long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
 #endif
 #ifdef HASH_STATISTICS
 long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
 #endif
@@ -73,10 +98,16 @@ __hash_open(file, flags, mode, info)
        int flags, mode;
        const HASHINFO *info;   /* Special directives for create */
 {
        int flags, mode;
        const HASHINFO *info;   /* Special directives for create */
 {
+       HTAB *hashp;
        struct stat statbuf;
        DB *dbp;
        int bpages, hdrsize, new_table, nsegs, save_errno;
 
        struct stat statbuf;
        DB *dbp;
        int bpages, hdrsize, new_table, nsegs, save_errno;
 
+       if ((flags & O_ACCMODE) == O_WRONLY) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
        if (!(hashp = calloc(1, sizeof(HTAB))))
                return (NULL);
        hashp->fp = -1;
        if (!(hashp = calloc(1, sizeof(HTAB))))
                return (NULL);
        hashp->fp = -1;
@@ -86,10 +117,7 @@ __hash_open(file, flags, mode, info)
         * But, the field in the hashp structure needs to be accurate so that
         * we can check accesses.
         */
         * But, the field in the hashp structure needs to be accurate so that
         * we can check accesses.
         */
-       hashp->flags = flags = flags & (O_CREAT | O_EXCL | O_EXLOCK | 
-           O_RDONLY | O_RDWR | O_SHLOCK | O_TRUNC | O_WRONLY);
-       if (flags & O_WRONLY)
-               flags = (flags & ~O_WRONLY) | O_RDWR;
+       hashp->flags = flags = flags & __USE_OPEN_FLAGS;
 
        new_table = 0;
        if (!file || (flags & O_TRUNC) ||
 
        new_table = 0;
        if (!file || (flags & O_TRUNC) ||
@@ -104,18 +132,18 @@ __hash_open(file, flags, mode, info)
                (void)fcntl(hashp->fp, F_SETFD, 1);
        }
        if (new_table) {
                (void)fcntl(hashp->fp, F_SETFD, 1);
        }
        if (new_table) {
-               if (!(hashp = init_hash((HASHINFO *)info)))
+               if (!(hashp = init_hash(hashp, file, (HASHINFO *)info)))
                        RETURN_ERROR(errno, error1);
        } else {
                /* Table already exists */
                if (info && info->hash)
                        hashp->hash = info->hash;
                else
                        RETURN_ERROR(errno, error1);
        } else {
                /* Table already exists */
                if (info && info->hash)
                        hashp->hash = info->hash;
                else
-                       hashp->hash = default_hash;
+                       hashp->hash = __default_hash;
 
                hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
 #if BYTE_ORDER == LITTLE_ENDIAN
 
                hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
 #if BYTE_ORDER == LITTLE_ENDIAN
-               swap_header();
+               swap_header(hashp);
 #endif
                if (hdrsize == -1)
                        RETURN_ERROR(errno, error1);
 #endif
                if (hdrsize == -1)
                        RETURN_ERROR(errno, error1);
@@ -136,7 +164,7 @@ __hash_open(file, flags, mode, info)
                nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
                         hashp->SGSIZE;
                hashp->nsegs = 0;
                nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
                         hashp->SGSIZE;
                hashp->nsegs = 0;
-               if (alloc_segs(nsegs))
+               if (alloc_segs(hashp, nsegs))
                        /*
                         * If alloc_segs fails, table will have been destroyed
                         * and errno will have been set.
                        /*
                         * If alloc_segs fails, table will have been destroyed
                         * and errno will have been set.
@@ -153,22 +181,23 @@ __hash_open(file, flags, mode, info)
 
        /* Initialize Buffer Manager */
        if (info && info->cachesize)
 
        /* Initialize Buffer Manager */
        if (info && info->cachesize)
-               __buf_init(info->cachesize);
+               __buf_init(hashp, info->cachesize);
        else
        else
-               __buf_init(DEF_BUFSIZE);
+               __buf_init(hashp, DEF_BUFSIZE);
 
        hashp->new_file = new_table;
 
        hashp->new_file = new_table;
-       hashp->save_file = file && (hashp->flags & (O_WRONLY | O_RDWR));
+       hashp->save_file = file && (hashp->flags & O_RDWR);
        hashp->cbucket = -1;
        if (!(dbp = malloc(sizeof(DB)))) {
                save_errno = errno;
        hashp->cbucket = -1;
        if (!(dbp = malloc(sizeof(DB)))) {
                save_errno = errno;
-               hdestroy();
+               hdestroy(hashp);
                errno = save_errno;
                return (NULL);
        }
                errno = save_errno;
                return (NULL);
        }
-       dbp->internal = (char *)hashp;
+       dbp->internal = hashp;
        dbp->close = hash_close;
        dbp->del = hash_delete;
        dbp->close = hash_close;
        dbp->del = hash_delete;
+       dbp->fd = hash_fd;
        dbp->get = hash_get;
        dbp->put = hash_put;
        dbp->seq = hash_seq;
        dbp->get = hash_get;
        dbp->put = hash_put;
        dbp->seq = hash_seq;
@@ -213,21 +242,43 @@ static int
 hash_close(dbp)
        DB *dbp;
 {
 hash_close(dbp)
        DB *dbp;
 {
+       HTAB *hashp;
        int retval;
 
        if (!dbp)
                return (ERROR);
        int retval;
 
        if (!dbp)
                return (ERROR);
+
        hashp = (HTAB *)dbp->internal;
        hashp = (HTAB *)dbp->internal;
-       retval = hdestroy();
+       retval = hdestroy(hashp);
        free(dbp);
        return (retval);
 }
 
        free(dbp);
        return (retval);
 }
 
+static int
+hash_fd(dbp)
+       const DB *dbp;
+{
+       HTAB *hashp;
+
+       if (!dbp)
+               return (ERROR);
+
+       hashp = (HTAB *)dbp->internal;
+       if (hashp->fp == -1) {
+               errno = ENOENT;
+               return (-1);
+       }
+       return (hashp->fp);
+}
+
 /************************** LOCAL CREATION ROUTINES **********************/
 static HTAB *
 /************************** LOCAL CREATION ROUTINES **********************/
 static HTAB *
-init_hash(info)
+init_hash(hashp, file, info)
+       HTAB *hashp;
+       const char *file;
        HASHINFO *info;
 {
        HASHINFO *info;
 {
+       struct stat statbuf;
        int nelem;
 
        nelem = 1;
        int nelem;
 
        nelem = 1;
@@ -239,9 +290,17 @@ init_hash(info)
        hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
        hashp->DSIZE = DEF_DIRSIZE;
        hashp->FFACTOR = DEF_FFACTOR;
        hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
        hashp->DSIZE = DEF_DIRSIZE;
        hashp->FFACTOR = DEF_FFACTOR;
-       hashp->hash = default_hash;
-       bzero(hashp->SPARES, sizeof(hashp->SPARES));
-       bzero (hashp->BITMAPS, sizeof (hashp->BITMAPS));
+       hashp->hash = __default_hash;
+       memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
+       memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
+
+       /* Fix bucket size to be optimal for file system */
+       if (file != NULL) {
+               if (stat(file, &statbuf))
+                       return (NULL);
+               hashp->BSIZE = statbuf.st_blksize;
+               hashp->BSHIFT = __log2(hashp->BSIZE);
+       }
 
        if (info) {
                if (info->bsize) {
 
        if (info) {
                if (info->bsize) {
@@ -269,7 +328,7 @@ init_hash(info)
                }
        }
        /* init_htab should destroy the table and set errno if it fails */
                }
        }
        /* init_htab should destroy the table and set errno if it fails */
-       if (init_htab(nelem))
+       if (init_htab(hashp, nelem))
                return (NULL);
        else
                return (hashp);
                return (NULL);
        else
                return (hashp);
@@ -281,7 +340,8 @@ init_hash(info)
  * Returns 0 on No Error
  */
 static int
  * Returns 0 on No Error
  */
 static int
-init_htab(nelem)
+init_htab(hashp, nelem)
+       HTAB *hashp;
        int nelem;
 {
        register int nbuckets, nsegs;
        int nelem;
 {
        register int nbuckets, nsegs;
@@ -303,7 +363,7 @@ init_htab(nelem)
        hashp->LAST_FREED = 2;
 
        /* First bitmap page is at: splitpoint l2 page offset 1 */
        hashp->LAST_FREED = 2;
 
        /* First bitmap page is at: splitpoint l2 page offset 1 */
-       if (__init_bitmap(OADDR_OF(l2, 1), l2 + 1, 0))
+       if (__init_bitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
                return (-1);
 
        hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
                return (-1);
 
        hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
@@ -316,7 +376,7 @@ init_htab(nelem)
 
        if (nsegs > hashp->DSIZE)
                hashp->DSIZE = nsegs;
 
        if (nsegs > hashp->DSIZE)
                hashp->DSIZE = nsegs;
-       return (alloc_segs(nsegs));
+       return (alloc_segs(hashp, nsegs));
 }
 
 /********************** DESTROY/CLOSE ROUTINES ************************/
 }
 
 /********************** DESTROY/CLOSE ROUTINES ************************/
@@ -326,52 +386,50 @@ init_htab(nelem)
  * structure, freeing all allocated space.
  */
 static int
  * structure, freeing all allocated space.
  */
 static int
-hdestroy()
+hdestroy(hashp)
+       HTAB *hashp;
 {
        int i, save_errno;
 
        save_errno = 0;
 
 {
        int i, save_errno;
 
        save_errno = 0;
 
-       if (hashp != NULL) {
 #ifdef HASH_STATISTICS
 #ifdef HASH_STATISTICS
-               (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
-                   hash_accesses, hash_collisions);
-               (void)fprintf(stderr, "hdestroy: expansions %ld\n",
-                   hash_expansions);
-               (void)fprintf(stderr, "hdestroy: overflows %ld\n",
-                   hash_overflows);
-               (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
-                   hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
-
-               for (i = 0; i < NCACHED; i++)
-                       (void)fprintf(stderr,
-                           "spares[%d] = %d\n", i, hashp->SPARES[i]);
+       (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
+           hash_accesses, hash_collisions);
+       (void)fprintf(stderr, "hdestroy: expansions %ld\n",
+           hash_expansions);
+       (void)fprintf(stderr, "hdestroy: overflows %ld\n",
+           hash_overflows);
+       (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
+           hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
+
+       for (i = 0; i < NCACHED; i++)
+               (void)fprintf(stderr,
+                   "spares[%d] = %d\n", i, hashp->SPARES[i]);
 #endif
 #endif
-               /*
-                * Call on buffer manager to free buffers, and if required,
-                * write them to disk.
-                */
-               if (__buf_free(1, hashp->save_file))
-                       save_errno = errno;
-               if (hashp->dir) {
-                       free(*hashp->dir);      /* Free initial segments */
-                       /* Free extra segments */
-                       while (hashp->exsegs--)
-                               free(hashp->dir[--hashp->nsegs]);
-                       free(hashp->dir);
-               }
-               if (flush_meta() && !save_errno)
-                       save_errno = errno;
-               /* Free Bigmaps */
-               for (i = 0; i < hashp->nmaps; i++)
-                       if (hashp->mapp[i])
-                               free(hashp->mapp[i]);
-
-               if (hashp->fp != -1)
-                       (void)close(hashp->fp);
-               free(hashp);
-               hashp = NULL;
+       /*
+        * Call on buffer manager to free buffers, and if required,
+        * write them to disk.
+        */
+       if (__buf_free(hashp, 1, hashp->save_file))
+               save_errno = errno;
+       if (hashp->dir) {
+               free(*hashp->dir);      /* Free initial segments */
+               /* Free extra segments */
+               while (hashp->exsegs--)
+                       free(hashp->dir[--hashp->nsegs]);
+               free(hashp->dir);
        }
        }
+       if (flush_meta(hashp) && !save_errno)
+               save_errno = errno;
+       /* Free Bigmaps */
+       for (i = 0; i < hashp->nmaps; i++)
+               if (hashp->mapp[i])
+                       free(hashp->mapp[i]);
+
+       if (hashp->fp != -1)
+               (void)close(hashp->fp);
+
        if (save_errno) {
                errno = save_errno;
                return (ERROR);
        if (save_errno) {
                errno = save_errno;
                return (ERROR);
@@ -386,16 +444,24 @@ hdestroy()
  *     -1 ERROR
  */
 static int
  *     -1 ERROR
  */
 static int
-hash_sync(dbp)
+hash_sync(dbp, flags)
        const DB *dbp;
        const DB *dbp;
+       u_int flags;
 {
 {
+       HTAB *hashp;
+
+       if (flags != 0) {
+               errno = EINVAL;
+               return (ERROR);
+       }
+
        if (!dbp)
                return (ERROR);
        if (!dbp)
                return (ERROR);
-       hashp = (HTAB *)dbp->internal;
 
 
+       hashp = (HTAB *)dbp->internal;
        if (!hashp->save_file)
                return (0);
        if (!hashp->save_file)
                return (0);
-       if (__buf_free(0, 1) || flush_meta())
+       if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
                return (ERROR);
        hashp->new_file = 0;
        return (0);
                return (ERROR);
        hashp->new_file = 0;
        return (0);
@@ -407,7 +473,8 @@ hash_sync(dbp)
  *     -1 indicates that errno should be set
  */
 static int
  *     -1 indicates that errno should be set
  */
 static int
-flush_meta()
+flush_meta(hashp)
+       HTAB *hashp;
 {
        HASHHDR *whdrp;
 #if BYTE_ORDER == LITTLE_ENDIAN
 {
        HASHHDR *whdrp;
 #if BYTE_ORDER == LITTLE_ENDIAN
@@ -427,7 +494,7 @@ flush_meta()
        whdrp = &whdr;
        swap_header_copy(&hashp->hdr, whdrp);
 #endif
        whdrp = &whdr;
        swap_header_copy(&hashp->hdr, whdrp);
 #endif
-       if ((lseek(fp, 0, SEEK_SET) == -1) ||
+       if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
            ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
                return (-1);
        else
            ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
                return (-1);
        else
@@ -438,7 +505,7 @@ flush_meta()
                }
        for (i = 0; i < NCACHED; i++)
                if (hashp->mapp[i])
                }
        for (i = 0; i < NCACHED; i++)
                if (hashp->mapp[i])
-                       if (__put_page((char *)hashp->mapp[i],
+                       if (__put_page(hashp, (char *)hashp->mapp[i],
                                hashp->BITMAPS[i], 0, 1))
                                return (-1);
        return (0);
                                hashp->BITMAPS[i], 0, 1))
                                return (-1);
        return (0);
@@ -460,34 +527,35 @@ hash_get(dbp, key, data, flag)
        DBT *data;
        u_int flag;
 {
        DBT *data;
        u_int flag;
 {
+       HTAB *hashp;
+
+       hashp = (HTAB *)dbp->internal;
        if (flag) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
        if (flag) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
-       hashp = (HTAB *)dbp->internal;
-       if (hashp->flags & O_WRONLY) {
-               hashp->errno = errno = EPERM;
-               return (ERROR);
-       }
-       return (hash_access(HASH_GET, (DBT *)key, data));
+       return (hash_access(hashp, HASH_GET, (DBT *)key, data));
 }
 
 static int
 hash_put(dbp, key, data, flag)
        const DB *dbp;
 }
 
 static int
 hash_put(dbp, key, data, flag)
        const DB *dbp;
-       const DBT *key, *data;
+       DBT *key;
+       const DBT *data;
        u_int flag;
 {
        u_int flag;
 {
+       HTAB *hashp;
+
+       hashp = (HTAB *)dbp->internal;
        if (flag && flag != R_NOOVERWRITE) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
        if (flag && flag != R_NOOVERWRITE) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
-       hashp = (HTAB *)dbp->internal;
        if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
                hashp->errno = errno = EPERM;
                return (ERROR);
        }
        if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
                hashp->errno = errno = EPERM;
                return (ERROR);
        }
-       return (hash_access(flag == R_NOOVERWRITE ?
+       return (hash_access(hashp, flag == R_NOOVERWRITE ?
            HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
 }
 
            HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
 }
 
@@ -497,23 +565,26 @@ hash_delete(dbp, key, flag)
        const DBT *key;
        u_int flag;             /* Ignored */
 {
        const DBT *key;
        u_int flag;             /* Ignored */
 {
+       HTAB *hashp;
+
+       hashp = (HTAB *)dbp->internal;
        if (flag && flag != R_CURSOR) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
        if (flag && flag != R_CURSOR) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
-       hashp = (HTAB *)dbp->internal;
        if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
                hashp->errno = errno = EPERM;
                return (ERROR);
        }
        if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
                hashp->errno = errno = EPERM;
                return (ERROR);
        }
-       return (hash_access(HASH_DELETE, (DBT *)key, NULL));
+       return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
 }
 
 /*
  * Assume that hashp has been set in wrapper routine.
  */
 static int
 }
 
 /*
  * Assume that hashp has been set in wrapper routine.
  */
 static int
-hash_access(action, key, val)
+hash_access(hashp, action, key, val)
+       HTAB *hashp;
        ACTION action;
        DBT *key, *val;
 {
        ACTION action;
        DBT *key, *val;
 {
@@ -531,7 +602,7 @@ hash_access(action, key, val)
        off = hashp->BSIZE;
        size = key->size;
        kp = (char *)key->data;
        off = hashp->BSIZE;
        size = key->size;
        kp = (char *)key->data;
-       rbufp = __get_buf(__call_hash(kp, size), NULL, 0);
+       rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
        if (!rbufp)
                return (ERROR);
        save_bufp = rbufp;
        if (!rbufp)
                return (ERROR);
        save_bufp = rbufp;
@@ -542,7 +613,7 @@ hash_access(action, key, val)
                if (bp[1] >= REAL_KEY) {
                        /* Real key/data pair */
                        if (size == off - *bp &&
                if (bp[1] >= REAL_KEY) {
                        /* Real key/data pair */
                        if (size == off - *bp &&
-                           bcmp(kp, rbufp->page + *bp, size) == 0)
+                           memcmp(kp, rbufp->page + *bp, size) == 0)
                                goto found;
                        off = bp[1];
 #ifdef HASH_STATISTICS
                                goto found;
                        off = bp[1];
 #ifdef HASH_STATISTICS
@@ -551,7 +622,7 @@ hash_access(action, key, val)
                        bp += 2;
                        ndx += 2;
                } else if (bp[1] == OVFLPAGE) {
                        bp += 2;
                        ndx += 2;
                } else if (bp[1] == OVFLPAGE) {
-                       rbufp = __get_buf(*bp, rbufp, 0);
+                       rbufp = __get_buf(hashp, *bp, rbufp, 0);
                        if (!rbufp) {
                                save_bufp->flags &= ~BUF_PIN;
                                return (ERROR);
                        if (!rbufp) {
                                save_bufp->flags &= ~BUF_PIN;
                                return (ERROR);
@@ -562,16 +633,18 @@ hash_access(action, key, val)
                        ndx = 1;
                        off = hashp->BSIZE;
                } else if (bp[1] < REAL_KEY) {
                        ndx = 1;
                        off = hashp->BSIZE;
                } else if (bp[1] < REAL_KEY) {
-                       if ((ndx = __find_bigpair(rbufp, ndx, kp, size)) > 0)
+                       if ((ndx =
+                           __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
                                goto found;
                        if (ndx == -2) {
                                bufp = rbufp;
                                goto found;
                        if (ndx == -2) {
                                bufp = rbufp;
-                               if (!(pageno = __find_last_page(&bufp))) {
+                               if (!(pageno =
+                                   __find_last_page(hashp, &bufp))) {
                                        ndx = 0;
                                        rbufp = bufp;
                                        break;  /* FOR */
                                }
                                        ndx = 0;
                                        rbufp = bufp;
                                        break;  /* FOR */
                                }
-                               rbufp = __get_buf(pageno, bufp, 0);
+                               rbufp = __get_buf(hashp, pageno, bufp, 0);
                                if (!rbufp) {
                                        save_bufp->flags &= ~BUF_PIN;
                                        return (ERROR);
                                if (!rbufp) {
                                        save_bufp->flags &= ~BUF_PIN;
                                        return (ERROR);
@@ -591,7 +664,7 @@ hash_access(action, key, val)
        switch (action) {
        case HASH_PUT:
        case HASH_PUTNEW:
        switch (action) {
        case HASH_PUT:
        case HASH_PUTNEW:
-               if (__addel(rbufp, key, val)) {
+               if (__addel(hashp, rbufp, key, val)) {
                        save_bufp->flags &= ~BUF_PIN;
                        return (ERROR);
                } else {
                        save_bufp->flags &= ~BUF_PIN;
                        return (ERROR);
                } else {
@@ -613,7 +686,7 @@ found:
        case HASH_GET:
                bp = (u_short *)rbufp->page;
                if (bp[ndx + 1] < REAL_KEY) {
        case HASH_GET:
                bp = (u_short *)rbufp->page;
                if (bp[ndx + 1] < REAL_KEY) {
-                       if (__big_return(rbufp, ndx, val, 0))
+                       if (__big_return(hashp, rbufp, ndx, val, 0))
                                return (ERROR);
                } else {
                        val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
                                return (ERROR);
                } else {
                        val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
@@ -621,15 +694,18 @@ found:
                }
                break;
        case HASH_PUT:
                }
                break;
        case HASH_PUT:
-               if ((__delpair(rbufp, ndx)) || (__addel(rbufp, key, val))) {
+               if ((__delpair(hashp, rbufp, ndx)) ||
+                   (__addel(hashp, rbufp, key, val))) {
                        save_bufp->flags &= ~BUF_PIN;
                        return (ERROR);
                }
                break;
        case HASH_DELETE:
                        save_bufp->flags &= ~BUF_PIN;
                        return (ERROR);
                }
                break;
        case HASH_DELETE:
-               if (__delpair(rbufp, ndx))
+               if (__delpair(hashp, rbufp, ndx))
                        return (ERROR);
                break;
                        return (ERROR);
                break;
+       default:
+               abort();
        }
        save_bufp->flags &= ~BUF_PIN;
        return (SUCCESS);
        }
        save_bufp->flags &= ~BUF_PIN;
        return (SUCCESS);
@@ -643,17 +719,14 @@ hash_seq(dbp, key, data, flag)
 {
        register u_int bucket;
        register BUFHEAD *bufp;
 {
        register u_int bucket;
        register BUFHEAD *bufp;
+       HTAB *hashp;
        u_short *bp, ndx;
 
        u_short *bp, ndx;
 
+       hashp = (HTAB *)dbp->internal;
        if (flag && flag != R_FIRST && flag != R_NEXT) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
        if (flag && flag != R_FIRST && flag != R_NEXT) {
                hashp->errno = errno = EINVAL;
                return (ERROR);
        }
-       hashp = (HTAB *)dbp->internal;
-       if (hashp->flags & O_WRONLY) {
-               hashp->errno = errno = EPERM;
-               return (ERROR);
-       }
 #ifdef HASH_STATISTICS
        hash_accesses++;
 #endif
 #ifdef HASH_STATISTICS
        hash_accesses++;
 #endif
@@ -663,12 +736,12 @@ hash_seq(dbp, key, data, flag)
                hashp->cpage = NULL;
        }
 
                hashp->cpage = NULL;
        }
 
-       for (bp = NULL; !bp || !bp[0]; ++hashp->cbucket) {
+       for (bp = NULL; !bp || !bp[0]; ) {
                if (!(bufp = hashp->cpage)) {
                        for (bucket = hashp->cbucket;
                            bucket <= hashp->MAX_BUCKET;
                            bucket++, hashp->cndx = 1) {
                if (!(bufp = hashp->cpage)) {
                        for (bucket = hashp->cbucket;
                            bucket <= hashp->MAX_BUCKET;
                            bucket++, hashp->cndx = 1) {
-                               bufp = __get_buf(bucket, NULL, 0);
+                               bufp = __get_buf(hashp, bucket, NULL, 0);
                                if (!bufp)
                                        return (ERROR);
                                hashp->cpage = bufp;
                                if (!bufp)
                                        return (ERROR);
                                hashp->cpage = bufp;
@@ -690,18 +763,20 @@ hash_seq(dbp, key, data, flag)
 #endif
                while (bp[hashp->cndx + 1] == OVFLPAGE) {
                        bufp = hashp->cpage =
 #endif
                while (bp[hashp->cndx + 1] == OVFLPAGE) {
                        bufp = hashp->cpage =
-                           __get_buf(bp[hashp->cndx], bufp, 0);
+                           __get_buf(hashp, bp[hashp->cndx], bufp, 0);
                        if (!bufp)
                                return (ERROR);
                        bp = (u_short *)(bufp->page);
                        hashp->cndx = 1;
                }
                        if (!bufp)
                                return (ERROR);
                        bp = (u_short *)(bufp->page);
                        hashp->cndx = 1;
                }
-               if (!bp[0])
+               if (!bp[0]) {
                        hashp->cpage = NULL;
                        hashp->cpage = NULL;
+                       ++hashp->cbucket;
+               }
        }
        ndx = hashp->cndx;
        if (bp[ndx + 1] < REAL_KEY) {
        }
        ndx = hashp->cndx;
        if (bp[ndx + 1] < REAL_KEY) {
-               if (__big_keydata(bufp, key, data, 1))
+               if (__big_keydata(hashp, bufp, key, data, 1))
                        return (ERROR);
        } else {
                key->data = (u_char *)hashp->cpage->page + bp[ndx];
                        return (ERROR);
        } else {
                key->data = (u_char *)hashp->cpage->page + bp[ndx];
@@ -727,7 +802,8 @@ hash_seq(dbp, key, data, flag)
  *     -1 ==> Error
  */
 extern int
  *     -1 ==> Error
  */
 extern int
-__expand_table()
+__expand_table(hashp)
+       HTAB *hashp;
 {
        u_int old_bucket, new_bucket;
        int dirsize, new_segnum, spare_ndx;
 {
        u_int old_bucket, new_bucket;
        int dirsize, new_segnum, spare_ndx;
@@ -773,7 +849,7 @@ __expand_table()
                hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
        }
        /* Relocate records to the new bucket */
                hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
        }
        /* Relocate records to the new bucket */
-       return (__split_page(old_bucket, new_bucket));
+       return (__split_page(hashp, old_bucket, new_bucket));
 }
 
 /*
 }
 
 /*
@@ -788,8 +864,8 @@ hash_realloc(p_ptr, oldsize, newsize)
        register void *p;
 
        if (p = malloc(newsize)) {
        register void *p;
 
        if (p = malloc(newsize)) {
-               bcopy(*p_ptr, p, oldsize);
-               bzero(*p_ptr + oldsize, newsize - oldsize);
+               memmove(p, *p_ptr, oldsize);
+               memset((char *)p + oldsize, 0, newsize - oldsize);
                free(*p_ptr);
                *p_ptr = p;
        }
                free(*p_ptr);
                *p_ptr = p;
        }
@@ -797,7 +873,8 @@ hash_realloc(p_ptr, oldsize, newsize)
 }
 
 extern u_int
 }
 
 extern u_int
-__call_hash(k, len)
+__call_hash(hashp, k, len)
+       HTAB *hashp;
        char *k;
        int len;
 {
        char *k;
        int len;
 {
@@ -816,7 +893,8 @@ __call_hash(k, len)
  * Returns 0 on success
  */
 static int
  * Returns 0 on success
  */
 static int
-alloc_segs(nsegs)
+alloc_segs(hashp, nsegs)
+       HTAB *hashp;
        int nsegs;
 {
        register int i;
        int nsegs;
 {
        register int i;
@@ -826,7 +904,7 @@ alloc_segs(nsegs)
 
        if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
                save_errno = errno;
 
        if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
                save_errno = errno;
-               (void)hdestroy();
+               (void)hdestroy(hashp);
                errno = save_errno;
                return (-1);
        }
                errno = save_errno;
                return (-1);
        }
@@ -834,7 +912,7 @@ alloc_segs(nsegs)
        store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT));
        if (!store) {
                save_errno = errno;
        store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT));
        if (!store) {
                save_errno = errno;
-               (void)hdestroy();
+               (void)hdestroy(hashp);
                errno = save_errno;
                return (-1);
        }
                errno = save_errno;
                return (-1);
        }
@@ -877,7 +955,8 @@ swap_header_copy(srcp, destp)
 }
 
 static void
 }
 
 static void
-swap_header()
+swap_header(hashp)
+       HTAB *hashp;
 {
        HASHHDR *hdrp;
        int i;
 {
        HASHHDR *hdrp;
        int i;