xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 46500)
146366Sbostic /*-
246366Sbostic  * Copyright (c) 1990 The Regents of the University of California.
346366Sbostic  * All rights reserved.
446366Sbostic  *
546366Sbostic  * This code is derived from software contributed to Berkeley by
646366Sbostic  * Margo Seltzer.
746366Sbostic  *
846366Sbostic  * %sccs.include.redist.c%
946366Sbostic  */
1046366Sbostic 
1146366Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*46500Sbostic static char sccsid[] = "@(#)hash.c	5.6 (Berkeley) 02/21/91";
1346366Sbostic #endif /* LIBC_SCCS and not lint */
1446366Sbostic 
1546366Sbostic #include <sys/param.h>
1646366Sbostic #include <sys/file.h>
1746366Sbostic #include <sys/stat.h>
1846366Sbostic #include <errno.h>
1946366Sbostic #include <assert.h>
2046366Sbostic #include <db.h>
21*46500Sbostic #include <unistd.h>
2246366Sbostic #include "hash.h"
2346366Sbostic #include <string.h>
2446366Sbostic 
2546366Sbostic /* Fast arithmetic, relying on powers of 2, */
2646366Sbostic 
2746366Sbostic #define MOD(x,y)		((x) & ((y)-1))
2846366Sbostic #define RETURN_ERROR(ERR,LOC)	{ save_errno = ERR; goto LOC; }
2946366Sbostic 
3046366Sbostic /* Return values */
3146366Sbostic 
3246366Sbostic #define	SUCCESS	0
3346366Sbostic #define	ERROR	-1
3446366Sbostic #define	ABNORMAL 1
3546366Sbostic 
3646366Sbostic /* external routines */
3746366Sbostic extern char *calloc();
3846366Sbostic 
3946366Sbostic /* page.c */
4046366Sbostic extern int __get_page();
4146366Sbostic extern int __split_page();
4246366Sbostic extern int __addel();
4346366Sbostic extern int __delpair();
4446366Sbostic extern u_long *__init_bitmap();
4546366Sbostic 
4646366Sbostic /* big.c */
4746366Sbostic extern void __big_return();
4846366Sbostic extern int __big_keydata();
4946366Sbostic extern u_short __find_last_page();
5046366Sbostic 
5146366Sbostic /* buf.c */
5246366Sbostic extern BUFHEAD	*__get_buf();
5346366Sbostic extern void __buf_init();
5446366Sbostic extern int __buf_free();
5546366Sbostic 
5646366Sbostic /* hash function */
5746366Sbostic extern int (*default_hash)();
5846366Sbostic 
5946366Sbostic /* My externals */
6046366Sbostic extern int __expand_table();
6146366Sbostic extern int __call_hash();
6246366Sbostic 
6346366Sbostic /* Internal routines */
6446366Sbostic static HTAB *init_hash();
6546366Sbostic static int hash_access();
6646366Sbostic static int flush_meta();
6746366Sbostic static int alloc_segs();
6846366Sbostic static int init_htab();
6946366Sbostic static char *hash_realloc();
7046366Sbostic static int hdestroy();
7146366Sbostic static int hash_put();
7246366Sbostic static int hash_delete();
7346366Sbostic static int hash_get();
7446366Sbostic static int hash_sync();
7546366Sbostic static int hash_close();
7646366Sbostic static int hash_seq();
7746366Sbostic static void swap_header_copy();
7846366Sbostic static void swap_header();
7946366Sbostic 
8046366Sbostic /* Local data */
8146366Sbostic 
8246366Sbostic HTAB *hashp = NULL;
8346366Sbostic 
8446366Sbostic #ifdef HASH_STATISTICS
8546366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
8646366Sbostic #endif
8746366Sbostic 
8846366Sbostic /************************** INTERFACE ROUTINES **********************/
8946366Sbostic /* OPEN/CLOSE */
9046366Sbostic 
9146366Sbostic extern	DB *
9246366Sbostic hash_open ( file, flags, mode, info )
9346366Sbostic char	*file;
9446366Sbostic int	flags;
9546366Sbostic int	mode;
9646366Sbostic HASHINFO	*info;		/* Special directives for create */
9746366Sbostic {
9846366Sbostic     int		buckets;
9946366Sbostic     int		bpages;
10046366Sbostic     int		hdrsize;
10146366Sbostic     int		i;
10246366Sbostic     int		new_table = 0;
10346366Sbostic     int		nkey;
10446366Sbostic     int		nsegs;
10546366Sbostic     int		save_errno;
10646366Sbostic     struct	stat statbuf;
10746366Sbostic     DB		*dbp;
10846366Sbostic 
10946366Sbostic 
11046366Sbostic     if ( !(hashp = (HTAB *) calloc( 1, sizeof(HTAB) ))) {
11146366Sbostic 	/* calloc should set errno */
11246366Sbostic 	return(0);
11346366Sbostic     }
11446457Sbostic     hashp->fp = -1;
11546366Sbostic     /*
11646366Sbostic 	Select flags relevant to us.
11746366Sbostic 	Even if user wants write only, we need to be able to read
11846366Sbostic 	the actual file, so we need to open it read/write.  But, the
11946366Sbostic 	field in the hashp structure needs to be accurate so that
12046366Sbostic 	we can check accesses.
12146366Sbostic     */
12246366Sbostic     flags = flags & (O_CREAT | O_EXCL | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY);
12346366Sbostic     hashp->flags = flags;
12446366Sbostic     if ( flags & O_WRONLY )  flags = (flags & ~O_WRONLY) | O_RDWR;
12546366Sbostic 
12646366Sbostic     if ( !file ||
12746366Sbostic 	 (flags & O_TRUNC) ||
12846366Sbostic 	 (stat ( file, &statbuf ) && (errno == ENOENT)) ) {
12946366Sbostic 	 new_table = 1;
13046366Sbostic     }
13146366Sbostic 
13246485Sbostic     if ( file ) {
13346485Sbostic 	if ((hashp->fp = open ( file, flags, mode )) == -1) {
13446485Sbostic 	    RETURN_ERROR (errno, error0);
13546485Sbostic 	}
13646485Sbostic 	(void)fcntl(hashp->fp, F_SETFD, 1);
13746366Sbostic     }
13846366Sbostic 
13946366Sbostic     if ( new_table ) {
14046366Sbostic 	if ( !(hashp = init_hash( info )) ) {
14146366Sbostic 	    RETURN_ERROR(errno,error1);
14246366Sbostic 	}
14346366Sbostic     } else {
14446366Sbostic 	/* Table already exists */
14546366Sbostic 	if ( info && info->hash ) hashp->hash = info->hash;
14646366Sbostic 	else hashp->hash = default_hash;
14746366Sbostic 
14846366Sbostic 	hdrsize = read ( hashp->fp, &hashp->hdr, sizeof(HASHHDR) );
14946366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
15046366Sbostic 	swap_header ( );
15146366Sbostic #endif
15246366Sbostic 	if ( hdrsize == -1 ) {
15346366Sbostic 	    RETURN_ERROR(errno, error1);
15446366Sbostic 	}
15546366Sbostic 	if ( hdrsize != sizeof(HASHHDR) ) {
15646366Sbostic 	    RETURN_ERROR(EFTYPE, error1);
15746366Sbostic 	}
15846366Sbostic 
15946366Sbostic 	/* Verify file type, versions and hash function */
16046366Sbostic 	if ( hashp->MAGIC != HASHMAGIC )
16146366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
16246366Sbostic 	if ( hashp->VERSION != VERSION_NO )
16346366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
16446366Sbostic 	if (hashp->hash ( CHARKEY, sizeof(CHARKEY) ) != hashp->H_CHARKEY ) {
16546366Sbostic 	    RETURN_ERROR ( EFTYPE, error1 );
16646366Sbostic 	}
16746366Sbostic 
16846366Sbostic 	/*
16946366Sbostic 	    Figure out how many segments we need.
17046366Sbostic 	*/
17146366Sbostic 	nsegs = (hashp->MAX_BUCKET + hashp->SGSIZE -1)/ hashp->SGSIZE;
17246366Sbostic 	hashp->nsegs = 0;
17346366Sbostic 	if (alloc_segs( nsegs )) {
17446366Sbostic 	    /*
17546366Sbostic 		If alloc_segs fails, table will have been destroyed
17646366Sbostic 		and errno will have been set.
17746366Sbostic 	    */
17846366Sbostic 	    return( (DB *) NULL );
17946366Sbostic 	}
18046366Sbostic 
18146366Sbostic 	/* Read in bitmaps */
18246366Sbostic 	bpages = (hashp->SPARES[__log2(hashp->MAX_BUCKET)] +
18346366Sbostic 		  (hashp->BSIZE << BYTE_SHIFT) - 1) >>
18446366Sbostic 		  (hashp->BSHIFT + BYTE_SHIFT);
18546366Sbostic 
18646366Sbostic 	hashp->mapp[0] = (u_long *)malloc(bpages<<hashp->BSHIFT);
18746366Sbostic 	if ( !hashp->mapp[0] ) {
18846366Sbostic 	    RETURN_ERROR(errno, error2);
18946366Sbostic 	}
19046366Sbostic 	for ( i = 0; i < bpages; i++ ) {
19146366Sbostic 	    hashp->mapp[i] = &hashp->mapp[0][i<<hashp->BSHIFT];
19246366Sbostic 	    if (__get_page ((char *)hashp->mapp[i],
19346366Sbostic 		hashp->BITMAPS[i], 0, 1, 1)) {
19446366Sbostic 		    RETURN_ERROR(errno, error2);
19546366Sbostic 	    }
19646366Sbostic 	}
19746366Sbostic 
19846366Sbostic     }
19946366Sbostic 
20046366Sbostic     /* Initialize Buffer Manager */
20146366Sbostic     if ( info && info->ncached ) {
20246366Sbostic 	__buf_init (info->ncached);
20346366Sbostic     } else {
20446366Sbostic 	__buf_init (DEF_BUFSIZE);
20546366Sbostic     }
20646366Sbostic 
20746366Sbostic     hashp->new_file = new_table;
20846457Sbostic     hashp->save_file = file && !(hashp->flags&O_RDONLY);
20946366Sbostic     hashp->cbucket = -1;
21046366Sbostic     if ( !(dbp = (DB *)malloc ( sizeof (DB) )) ) {
21146366Sbostic 	save_errno = errno;
21246366Sbostic 	hdestroy();
21346366Sbostic 	errno = save_errno;
21446366Sbostic 	return ( NULL );
21546366Sbostic     }
21646366Sbostic     dbp->internal = (char *)hashp;
21746366Sbostic     dbp->close = hash_close;
21846366Sbostic     dbp->delete = hash_delete;
21946366Sbostic     dbp->get = hash_get;
22046366Sbostic     dbp->put = hash_put;
22146366Sbostic     dbp->seq = hash_seq;
22246366Sbostic     dbp->sync = hash_sync;
22346366Sbostic 
22446366Sbostic #ifdef DEBUG
22546366Sbostic 	(void)fprintf(stderr, "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
22646366Sbostic 		"init_htab:",
22746366Sbostic 		"TABLE POINTER   ", hashp,
22846366Sbostic 		"BUCKET SIZE     ", hashp->BSIZE,
22946366Sbostic 		"BUCKET SHIFT    ", hashp->BSHIFT,
23046366Sbostic 		"DIRECTORY SIZE  ", hashp->DSIZE,
23146366Sbostic 		"SEGMENT SIZE    ", hashp->SGSIZE,
23246366Sbostic 		"SEGMENT SHIFT   ", hashp->SSHIFT,
23346366Sbostic 		"FILL FACTOR     ", hashp->FFACTOR,
23446366Sbostic 		"MAX BUCKET      ", hashp->MAX_BUCKET,
23546366Sbostic 		"HIGH MASK       ", hashp->HIGH_MASK,
23646366Sbostic 		"LOW  MASK       ", hashp->LOW_MASK,
23746366Sbostic 		"NSEGS           ", hashp->nsegs,
23846366Sbostic 		"NKEYS           ", hashp->NKEYS );
23946366Sbostic #endif
24046366Sbostic #ifdef HASH_STATISTICS
24146366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
24246366Sbostic #endif
24346366Sbostic     return (dbp);
24446366Sbostic 
24546366Sbostic error2:
24646366Sbostic     (void)hdestroy();
24746366Sbostic     errno = save_errno;
24846366Sbostic     return ( (DB *)NULL );
24946366Sbostic 
25046366Sbostic error1:
25146366Sbostic     (void) close ( hashp->fp );
25246366Sbostic 
25346366Sbostic error0:
25446366Sbostic     free ( hashp );
25546366Sbostic     errno = save_errno;
25646366Sbostic     return ( (DB *) NULL );
25746366Sbostic }
25846366Sbostic 
25946366Sbostic static int
26046366Sbostic hash_close (dbp)
26146366Sbostic DB	*dbp;
26246366Sbostic {
26346457Sbostic 	int	retval;
26446457Sbostic 
26546366Sbostic 	if ( !dbp ) {
26646366Sbostic 	    return(ERROR);
26746366Sbostic 	}
26846366Sbostic 	hashp = (HTAB *)dbp->internal;
26946457Sbostic 	retval = hdestroy();
27046457Sbostic 	(void)free ( dbp );
27146457Sbostic 	return ( retval );
27246366Sbostic }
27346366Sbostic 
27446366Sbostic 
27546366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
27646366Sbostic static HTAB *
27746366Sbostic init_hash( info )
27846366Sbostic HASHINFO *info;
27946366Sbostic {
28046366Sbostic 	int	nelem;
28146366Sbostic 
28246366Sbostic 	nelem = 1;
28346366Sbostic 
28446366Sbostic 	hashp->LORDER	= BYTE_ORDER;
28546366Sbostic 	hashp->BSIZE    = DEF_BUCKET_SIZE;
28646366Sbostic 	hashp->BSHIFT   = DEF_BUCKET_SHIFT;
28746366Sbostic 	hashp->SGSIZE   = DEF_SEGSIZE;
28846366Sbostic 	hashp->SSHIFT   = DEF_SEGSIZE_SHIFT;
28946366Sbostic 	hashp->DSIZE    = DEF_DIRSIZE;
29046366Sbostic 	hashp->FFACTOR  = DEF_FFACTOR;
29146366Sbostic 	hashp->hash     = default_hash;
29246366Sbostic 	bzero (hashp->SPARES, sizeof (hashp->SPARES));
29346366Sbostic 
29446366Sbostic 	if ( info ) {
29546366Sbostic 	    if ( info->bsize )   {
29646366Sbostic 		/* Round pagesize up to power of 2 */
29746366Sbostic 		hashp->BSHIFT  = __log2(info->bsize);
29846366Sbostic 		hashp->BSIZE   = 1 << hashp->BSHIFT;
29946366Sbostic 		if ( hashp->BSIZE > MAX_BSIZE ) {
30046366Sbostic 		    errno = EINVAL;
30146366Sbostic 		    return(0);
30246366Sbostic 		}
30346366Sbostic 	    }
30446366Sbostic 	    if ( info->ffactor )  hashp->FFACTOR = info->ffactor;
30546366Sbostic 	    if ( info->hash ) hashp->hash    = info->hash;
30646366Sbostic 	    if ( info->nelem ) nelem = info->nelem;
30746366Sbostic 	    if ( info->lorder ) {
30846366Sbostic 		if ( info->lorder != BIG_ENDIAN &&
30946366Sbostic 		     info->lorder != LITTLE_ENDIAN) {
31046366Sbostic 		    errno = EINVAL;
31146366Sbostic 		    return(0);
31246366Sbostic 		}
31346366Sbostic 		hashp->LORDER = info->lorder;
31446366Sbostic 	    }
31546366Sbostic 	}
31646366Sbostic 
31746366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
31846366Sbostic 	if ( init_htab ( nelem ) ) {
31946366Sbostic 	    return(0);
32046366Sbostic 	} else {
32146366Sbostic 	    return(hashp);
32246366Sbostic 	}
32346366Sbostic }
32446366Sbostic 
32546366Sbostic /*
32646366Sbostic     This calls alloc_segs which may run out of memory.
32746366Sbostic     Alloc_segs will destroy the table and set errno,
32846366Sbostic     so we just pass the error information along.
32946366Sbostic 
33046366Sbostic     Returns 0 on No Error
33146366Sbostic 
33246366Sbostic */
33346366Sbostic static int
33446366Sbostic init_htab ( nelem )
33546366Sbostic int	nelem;
33646366Sbostic {
33746366Sbostic 	register SEGMENT	*segp;
33846366Sbostic 	register int nbuckets;
33946366Sbostic 	register int nsegs;
34046366Sbostic 	int	l2;
34146366Sbostic 
34246366Sbostic  /*
34346366Sbostic   * Divide number of elements by the fill factor and determine a desired
34446366Sbostic   * number of buckets.  Allocate space for the next greater power of
34546366Sbostic   * two number of buckets
34646366Sbostic   */
34746366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
34846366Sbostic 
34946366Sbostic 	l2 = __log2(nelem);
35046366Sbostic 	nbuckets = 1 << l2;
35146366Sbostic 	nbuckets = MAX ( nbuckets, 2 );
35246366Sbostic 
35346366Sbostic 	hashp->SPARES[l2] = l2 + 1;
35446366Sbostic 	hashp->SPARES[l2+1] = l2 + 1;
35546366Sbostic 	/*
35646366Sbostic 	    First bitmap page is at:
35746366Sbostic 		splitpoint l2
35846366Sbostic 		page offset 1
35946366Sbostic 	*/
36046366Sbostic 	__init_bitmap ( OADDR_OF(l2,1), l2+1, 0 );
36146366Sbostic 
36246366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
36346366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
36446366Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR),MINHDRSIZE) - 1) >>
36546366Sbostic 			  hashp->BSHIFT) + 1;
36646366Sbostic 
36746366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
36846366Sbostic 	nsegs = 1 << __log2(nsegs);
36946366Sbostic 
37046366Sbostic 	if ( nsegs > hashp->DSIZE ) {
37146366Sbostic 	    hashp->DSIZE  = nsegs;
37246366Sbostic 	}
37346366Sbostic 
37446366Sbostic 	return (alloc_segs ( nsegs ) );
37546366Sbostic }
37646366Sbostic 
37746366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
37846366Sbostic 
37946366Sbostic /*
38046366Sbostic     Flushes any changes to the file if necessary and
38146366Sbostic     destroys the hashp structure, freeing all allocated
38246366Sbostic     space.
38346366Sbostic */
38446366Sbostic static int
38546366Sbostic hdestroy()
38646366Sbostic {
38746366Sbostic 	int	save_errno;
38846366Sbostic 	int	i;
38946366Sbostic 
39046366Sbostic 	save_errno = 0;
39146366Sbostic 
39246366Sbostic 	if (hashp != NULL) {
39346366Sbostic #ifdef HASH_STATISTICS
39446366Sbostic 	 (void)	fprintf(stderr,	"hdestroy: accesses %ld collisions %ld\n",
39546366Sbostic 			hash_accesses, hash_collisions);
39646366Sbostic 	 (void)	fprintf(stderr, "hdestroy: expansions %ld\n",
39746366Sbostic 			hash_expansions);
39846366Sbostic 	 (void)	fprintf(stderr, "hdestroy: overflows %ld\n",
39946366Sbostic 			hash_overflows);
40046366Sbostic 	 (void)	fprintf(stderr,	"keys %ld maxp %d segmentcount %d\n",
40146366Sbostic 			hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
40246366Sbostic 
40346366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
40446366Sbostic 	    (void) fprintf ( stderr, "spares[%d] = %d\n", i, hashp->SPARES[i] );
40546366Sbostic 	}
40646366Sbostic #endif
40746366Sbostic 
40846366Sbostic 		/*
40946366Sbostic 		    Call on buffer manager to free buffers, and if
41046366Sbostic 		    required, write them to disk
41146366Sbostic 		*/
41246366Sbostic 		if (__buf_free(1, hashp->save_file)) {
41346366Sbostic 		    save_errno = errno;
41446366Sbostic 		}
41546366Sbostic 		if ( hashp->dir ) {
41646366Sbostic 		    (void)free(*hashp->dir);	/* Free initial segments */
41746366Sbostic 		    /* Free extra segments */
41846366Sbostic 		    while ( hashp->exsegs-- ) {
41946366Sbostic 			(void)free ( hashp->dir[--hashp->nsegs] );
42046366Sbostic 		    }
42146366Sbostic 		    (void)free(hashp->dir);
42246366Sbostic 		}
42346366Sbostic 		if (flush_meta() && !save_errno) {
42446366Sbostic 		    save_errno = errno;
42546366Sbostic 		}
42646457Sbostic 		if ( hashp->fp != -1 ) {
42746457Sbostic 			(void)close (hashp->fp);
42846457Sbostic 		}
42946366Sbostic 		(void)free(hashp);
43046366Sbostic 		hashp = NULL;
43146366Sbostic 	}
43246366Sbostic 	if ( save_errno ) {
43346366Sbostic 	    errno = save_errno;
43446366Sbostic 	    return(ERROR);
43546366Sbostic 	} else {
43646366Sbostic 	    return(SUCCESS);
43746366Sbostic 	}
43846366Sbostic }
43946366Sbostic 
44046366Sbostic /*
44146366Sbostic     Write modified pages to disk
44246366Sbostic     0 == OK
44346366Sbostic     -1 ERROR
44446366Sbostic */
44546366Sbostic static int
44646366Sbostic hash_sync(dbp)
44746366Sbostic DB	*dbp;
44846366Sbostic {
44946366Sbostic 	if ( !dbp ) {
45046366Sbostic 	    return (ERROR);
45146366Sbostic 	}
45246366Sbostic 
45346366Sbostic 	hashp = (HTAB *)dbp->internal;
45446366Sbostic 
45546366Sbostic 	if (!hashp->save_file) return(0);
45646366Sbostic 	if ( __buf_free ( 0, 1 )  || flush_meta()) {
45746366Sbostic 	    return(ERROR);
45846366Sbostic 	}
45946366Sbostic 	hashp->new_file = 0;
46046366Sbostic 	return(0);
46146366Sbostic }
46246366Sbostic 
46346366Sbostic /*
46446366Sbostic 0 == OK
46546366Sbostic -1 indicates that errno should be set
46646366Sbostic */
46746366Sbostic static int
46846366Sbostic flush_meta()
46946366Sbostic {
47046366Sbostic     	int	fp;
47146366Sbostic 	int	hdrsize;
47246366Sbostic 	int	i;
47346366Sbostic 	int	wsize;
47446366Sbostic 	HASHHDR	*whdrp;
47546366Sbostic 	HASHHDR	whdr;
47646366Sbostic 
47746366Sbostic 	if (!hashp->save_file) return(0);
47846366Sbostic 	hashp->MAGIC = HASHMAGIC;
47946366Sbostic 	hashp->VERSION = VERSION_NO;
48046366Sbostic 	hashp->H_CHARKEY = hashp->hash ( CHARKEY, sizeof(CHARKEY));
48146366Sbostic 
48246366Sbostic 	fp = hashp->fp;
48346366Sbostic 	whdrp = &hashp->hdr;
48446366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
48546366Sbostic 	whdrp = &whdr;
48646366Sbostic 	swap_header_copy( &hashp->hdr, whdrp );
48746366Sbostic #endif
488*46500Sbostic 	if ( (lseek (fp, 0, SEEK_SET) == -1 ) ||
48946366Sbostic 	     ((wsize = write ( fp, whdrp, sizeof(HASHHDR))) == -1)) {
49046366Sbostic 	    return(-1);
49146366Sbostic 	} else if ( wsize != sizeof(HASHHDR) ) {
49246366Sbostic 	    errno = EFTYPE;
49346366Sbostic 	    hashp->errno = errno;
49446366Sbostic 	    return(-1);
49546366Sbostic 	}
49646366Sbostic 	for ( i = 0; i < NCACHED; i++ ) {
49746366Sbostic 	    if ( hashp->mapp[i] ) {
49846366Sbostic 		if (!__put_page((char *)hashp->mapp[i],
49946366Sbostic 		    hashp->BITMAPS[i], 0, 1)){
50046366Sbostic 		    return(-1);
50146366Sbostic 		}
50246366Sbostic 	    }
50346366Sbostic 	}
50446366Sbostic 	return(0);
50546366Sbostic }
50646366Sbostic /*******************************SEARCH ROUTINES *****************************/
50746366Sbostic /*
50846366Sbostic     All the access routines return
50946366Sbostic 	0 on SUCCESS
51046366Sbostic 	1 to indicate an external ERROR (i.e. key not found, etc)
51146366Sbostic 	-1 to indicate an internal ERROR (i.e. out of memory, etc)
51246366Sbostic */
51346366Sbostic static int
51446366Sbostic hash_get ( dbp, key, data )
51546366Sbostic DB	*dbp;
51646366Sbostic DBT *key, *data;
51746366Sbostic {
51846366Sbostic     if ( !dbp ) {
51946366Sbostic 	return (ERROR);
52046366Sbostic     }
52146366Sbostic     hashp = (HTAB *)dbp->internal;
52246366Sbostic     if ( hashp->flags & O_WRONLY ) {
52346366Sbostic 	errno = EBADF;
52446366Sbostic 	hashp->errno = errno;
52546366Sbostic 	return ( ERROR );
52646366Sbostic     }
52746366Sbostic     return ( hash_access ( HASH_GET, key, data ) );
52846366Sbostic }
52946366Sbostic 
53046366Sbostic static int
53146366Sbostic hash_put ( dbp, key, data, flag )
53246366Sbostic DB	*dbp;
53346366Sbostic DBT 	*key, *data;
53446366Sbostic int	flag;
53546366Sbostic {
53646366Sbostic     if ( !dbp ) {
53746366Sbostic 	return (ERROR);
53846366Sbostic     }
53946366Sbostic     hashp = (HTAB *)dbp->internal;
54046366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
54146366Sbostic 	errno = EBADF;
54246366Sbostic 	hashp->errno = errno;
54346366Sbostic 	return ( ERROR );
54446366Sbostic     }
54546366Sbostic     if ( flag == R_NOOVERWRITE ) {
54646366Sbostic 	return ( hash_access ( HASH_PUTNEW, key, data ) );
54746366Sbostic     } else {
54846366Sbostic 	return ( hash_access ( HASH_PUT, key, data ) );
54946366Sbostic     }
55046366Sbostic }
55146366Sbostic 
55246366Sbostic static int
55346366Sbostic hash_delete ( dbp, key, flags )
55446366Sbostic DB	*dbp;
55546366Sbostic DBT 	*key;
55646366Sbostic int	flags;		/* Ignored */
55746366Sbostic {
55846366Sbostic     if ( !dbp ) {
55946366Sbostic 	return (ERROR);
56046366Sbostic     }
56146366Sbostic     hashp = (HTAB *)dbp->internal;
56246366Sbostic     if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
56346366Sbostic 	errno = EBADF;
56446366Sbostic 	hashp->errno = errno;
56546366Sbostic 	return ( ERROR );
56646366Sbostic     }
56746366Sbostic     return ( hash_access ( HASH_DELETE, key, NULL ) );
56846366Sbostic }
56946366Sbostic 
57046366Sbostic /*
57146366Sbostic     Assume that hashp has been set in wrapper routine
57246366Sbostic */
57346366Sbostic static int
57446366Sbostic hash_access(action, key, val)
57546366Sbostic ACTION action;
57646366Sbostic DBT *key, *val;
57746366Sbostic {
57846366Sbostic 	register	BUFHEAD	*rbufp;
57946366Sbostic 	register	u_short	*bp;
58046366Sbostic 	register	int	ndx;
58146366Sbostic 	register 	int n;
58246366Sbostic 	register 	int off = hashp->BSIZE;
58346366Sbostic 	register	int		size;
58446366Sbostic 	register	char	*kp;
58546366Sbostic 	BUFHEAD	*bufp;
58646457Sbostic 	BUFHEAD	*save_bufp;
58746366Sbostic 	u_short	pageno;
58846366Sbostic 
58946366Sbostic #ifdef HASH_STATISTICS
59046366Sbostic 	hash_accesses++;
59146366Sbostic #endif
59246366Sbostic 
59346366Sbostic 	size = key->size;
59446366Sbostic 	kp = key->data;
59546457Sbostic 	rbufp = __get_buf ( __call_hash(kp, size), NULL, 0 );
59646366Sbostic 	if ( !rbufp ) return(ERROR);
59746457Sbostic 	save_bufp = rbufp;
59846366Sbostic 
59946457Sbostic 	/* Pin the bucket chain */
60046457Sbostic 	rbufp->flags |= BUF_PIN;
60146366Sbostic 	for ( bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;  ) {
60246366Sbostic 	    if ( bp[1] >= REAL_KEY ) {
60346366Sbostic 		/* Real key/data pair */
60446366Sbostic 		if (size == off - *bp &&
60546366Sbostic 		    bcmp(kp, rbufp->page + *bp, size) == 0) {
60646366Sbostic 		    goto found;
60746366Sbostic 		}
60846366Sbostic 		off = bp[1];
60946366Sbostic #ifdef HASH_STATISTICS
61046366Sbostic 		hash_collisions++;
61146366Sbostic #endif
61246366Sbostic 	        bp += 2;
61346366Sbostic 	        ndx += 2;
61446366Sbostic 	    } else if ( bp[1] == OVFLPAGE ) {
61546366Sbostic 		rbufp = __get_buf ( *bp, rbufp, 0 );
61646457Sbostic 		if ( !rbufp ) {
61746457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
61846457Sbostic 		    return (ERROR);
61946457Sbostic 		}
62046366Sbostic 		/* FOR LOOP INIT */
62146366Sbostic 		bp = (u_short *)rbufp->page;
62246366Sbostic 		n = *bp++;
62346366Sbostic 		ndx = 1;
62446366Sbostic 		off = hashp->BSIZE;
62546366Sbostic 	    } else if ( bp[1] < REAL_KEY ) {
62646366Sbostic 		if ( (ndx = __find_bigpair(rbufp, ndx, kp, size )) > 0 ) {
62746366Sbostic 		    goto found;
62846366Sbostic 		} else if ( ndx == -2 ) {
62946366Sbostic 		    bufp = rbufp;
63046366Sbostic 		    if ( !(pageno = __find_last_page ( &bufp )) ) {
63146366Sbostic 			ndx = 0;
63246366Sbostic 			rbufp = bufp;
63346366Sbostic 			break;	/* FOR */
63446366Sbostic 		    }
63546366Sbostic 		    rbufp = __get_buf ( pageno, bufp, 0 );
63646457Sbostic 		    if ( !rbufp ) {
63746457Sbostic 			save_bufp->flags &= ~BUF_PIN;
63846457Sbostic 			return (ERROR);
63946457Sbostic 		    }
64046366Sbostic 		    /* FOR LOOP INIT */
64146366Sbostic 		    bp = (u_short *)rbufp->page;
64246366Sbostic 		    n = *bp++;
64346366Sbostic 		    ndx = 1;
64446366Sbostic 		    off = hashp->BSIZE;
64546366Sbostic 		} else  {
64646457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
64746366Sbostic 		    return(ERROR);
64846366Sbostic 		}
64946366Sbostic 	    }
65046366Sbostic 	}
65146366Sbostic 
65246366Sbostic 	/* Not found */
65346366Sbostic 	switch ( action ) {
65446366Sbostic 	    case HASH_PUT:
65546366Sbostic 	    case HASH_PUTNEW:
65646366Sbostic 		if (__addel(rbufp, key, val)) {
65746457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
65846366Sbostic 		    return(ERROR);
65946366Sbostic 		} else {
66046457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
66146366Sbostic 		    return(SUCCESS);
66246366Sbostic 		}
66346366Sbostic 	    case HASH_GET:
66446366Sbostic 	    case HASH_DELETE:
66546366Sbostic 	    default:
66646457Sbostic 		save_bufp->flags &= ~BUF_PIN;
66746366Sbostic 		return(ABNORMAL);
66846366Sbostic 	}
66946366Sbostic 
67046366Sbostic found:
67146366Sbostic 	switch (action) {
67246366Sbostic 	    case HASH_PUTNEW:
67346457Sbostic 		save_bufp->flags &= ~BUF_PIN;
67446366Sbostic 		return(ABNORMAL);
67546366Sbostic 	    case HASH_GET:
67646366Sbostic 		bp = (u_short *)rbufp->page;
67746366Sbostic 		if (bp[ndx+1] < REAL_KEY) __big_return(rbufp, ndx, val, 0);
67846366Sbostic 		else {
67946366Sbostic 		    val->data = rbufp->page + (int) bp[ndx + 1];
68046366Sbostic 		    val->size = bp[ndx] - bp[ndx + 1];
68146366Sbostic 		}
68246366Sbostic 		break;
68346366Sbostic 	    case HASH_PUT:
68446457Sbostic 		if ((__delpair (rbufp, ndx)) || (__addel (rbufp, key, val)) ) {
68546457Sbostic 		    save_bufp->flags &= ~BUF_PIN;
68646457Sbostic 		    return(ERROR);
68746457Sbostic 		}
68846366Sbostic 		break;
68946366Sbostic 	    case HASH_DELETE:
69046366Sbostic 		if (__delpair (rbufp, ndx))return(ERROR);
69146366Sbostic 		break;
69246366Sbostic 	}
69346457Sbostic 	save_bufp->flags &= ~BUF_PIN;
69446366Sbostic 	return (SUCCESS);
69546366Sbostic }
69646366Sbostic 
69746366Sbostic static int
69846366Sbostic hash_seq(dbp, key, data, flag)
69946366Sbostic DB	*dbp;
70046366Sbostic DBT 	*key, *data;
70146366Sbostic int flag;
70246366Sbostic {
70346366Sbostic 	register	int bucket;
70446366Sbostic 	register	BUFHEAD	*bufp;
70546457Sbostic 	BUFHEAD	*save_bufp;
70646366Sbostic 	u_short	*bp;
70746366Sbostic 	u_short	ndx;
70846366Sbostic 	u_short	pageno;
70946366Sbostic 
71046366Sbostic 	if ( !dbp ) {
71146366Sbostic 	    return (ERROR);
71246366Sbostic 	}
71346366Sbostic 
71446366Sbostic 	hashp = (HTAB *)dbp->internal;
71546366Sbostic 	if ( hashp->flags & O_WRONLY ) {
71646366Sbostic 	    errno = EBADF;
71746366Sbostic 	    hashp->errno = errno;
71846366Sbostic 	    return ( ERROR );
71946366Sbostic 	}
72046366Sbostic #ifdef HASH_STATISTICS
72146366Sbostic 	hash_accesses++;
72246366Sbostic #endif
72346366Sbostic 
72446366Sbostic 	if ( (hashp->cbucket < 0) || (flag == R_FIRST) ) {
72546366Sbostic 	    hashp->cbucket = 0;
72646366Sbostic 	    hashp->cndx = 1;
72746366Sbostic 	    hashp->cpage = NULL;
72846366Sbostic 	}
72946366Sbostic 
73046366Sbostic 	if ( !(bufp = hashp->cpage) ) {
73146366Sbostic 	    for (bucket = hashp->cbucket;
73246366Sbostic 		 bucket <= hashp->MAX_BUCKET;
73346366Sbostic 		 bucket++, hashp->cndx = 1 ) {
73446366Sbostic 
73546366Sbostic 		bufp = __get_buf ( bucket, NULL, 0 );
73646366Sbostic 		if (!bufp) return(ERROR);
73746366Sbostic 		hashp->cpage = bufp;
73846366Sbostic 		bp = (u_short *)bufp->page;
73946366Sbostic 		if (bp[0]) break;
74046366Sbostic 	    }
74146366Sbostic 	    hashp->cbucket = bucket;
74246366Sbostic 	    if ( hashp->cbucket > hashp->MAX_BUCKET ) {
74346366Sbostic 		hashp->cbucket = -1;
74446366Sbostic 		return ( ABNORMAL );
74546366Sbostic 	    }
74646366Sbostic 	} else {
74746366Sbostic 	    bp  = (u_short *)hashp->cpage->page;
74846366Sbostic 	}
74946366Sbostic 
75046366Sbostic #ifdef DEBUG
75146366Sbostic 	assert (bp);
75246366Sbostic 	assert (bufp);
75346366Sbostic #endif
75446366Sbostic 	while ( bp[hashp->cndx+1] == OVFLPAGE ) {
75546366Sbostic 	    bufp = hashp->cpage = __get_buf ( bp[hashp->cndx], bufp, 0 );
75646366Sbostic 	    if (!bufp) return(ERROR);
75746366Sbostic 	    bp = (u_short *)(bufp->page);
75846366Sbostic 	    hashp->cndx = 1;
75946366Sbostic 	}
76046366Sbostic 	ndx = hashp->cndx;
76146366Sbostic 	if (bp[ndx+1] < REAL_KEY) {
76246366Sbostic 	    if (__big_keydata(bufp, ndx, key, data, 1)) {
76346366Sbostic 		return(ERROR);
76446366Sbostic 	    }
76546366Sbostic 	} else {
76646366Sbostic 	    key->data = hashp->cpage->page + bp[ndx];
76746366Sbostic 	    key->size = (ndx > 1 ? bp[ndx-1] : hashp->BSIZE) - bp[ndx];
76846366Sbostic 	    data->data = hashp->cpage->page + bp[ndx + 1];
76946366Sbostic 	    data->size = bp[ndx] - bp[ndx + 1];
77046366Sbostic 	    ndx += 2;
77146366Sbostic 	    if ( ndx > bp[0] ) {
77246366Sbostic 		hashp->cpage = NULL;
77346366Sbostic 		hashp->cbucket++;
77446366Sbostic 		hashp->cndx=1;
77546366Sbostic 	    } else hashp->cndx = ndx;
77646366Sbostic 	}
77746366Sbostic 	return (SUCCESS);
77846366Sbostic }
77946366Sbostic 
78046366Sbostic /********************************* UTILITIES ************************/
78146366Sbostic /*
78246366Sbostic     0 ==> OK
78346366Sbostic     -1 ==> Error
78446366Sbostic */
78546366Sbostic extern int
78646366Sbostic __expand_table()
78746366Sbostic {
78846366Sbostic 	int	old_bucket, new_bucket;
78946366Sbostic 	int	new_segnum;
79046366Sbostic 	int	dirsize;
79146366Sbostic 	int	spare_ndx;
79246366Sbostic 	register	char **old, **new;
79346366Sbostic #ifdef HASH_STATISTICS
79446366Sbostic 	hash_expansions++;
79546366Sbostic #endif
79646366Sbostic 
79746366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
79846366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
79946366Sbostic 
80046366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
80146366Sbostic 
80246366Sbostic 	/* Check if we need a new segment */
80346366Sbostic 	if ( new_segnum >= hashp->nsegs ) {
80446366Sbostic 
80546366Sbostic 	    /* Check if we need to expand directory */
80646366Sbostic 	    if ( new_segnum >= hashp->DSIZE ) {
80746366Sbostic 
80846366Sbostic 		/* Reallocate directory */
80946366Sbostic 		dirsize = hashp->DSIZE * sizeof ( SEGMENT * );
81046366Sbostic 		if (!hash_realloc ( &hashp->dir, dirsize, (dirsize << 1 ) )) {
81146366Sbostic 		    return(-1);
81246366Sbostic 		}
81346366Sbostic 		hashp->DSIZE = dirsize << 1;
81446366Sbostic 	    }
81546366Sbostic 	    if (!(hashp->dir[new_segnum] =
81646366Sbostic 		    (SEGMENT)calloc ( hashp->SGSIZE, sizeof(SEGMENT)))) {
81746366Sbostic 		    return(-1);
81846366Sbostic 	    }
81946366Sbostic 	    hashp->exsegs++;
82046366Sbostic 	    hashp->nsegs++;
82146366Sbostic 	}
82246366Sbostic 
82346366Sbostic 	/*
82446366Sbostic 	    If the split point is increasing (MAX_BUCKET's log
82546366Sbostic 	    base 2 increases), we need to copy the current contents
82646366Sbostic 	    of the spare split bucket to the next bucket
82746366Sbostic 	*/
82846366Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET);
82946366Sbostic 	if ( spare_ndx != (__log2(hashp->MAX_BUCKET - 1))) {
83046366Sbostic 	    hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx-1];
83146366Sbostic 	}
83246366Sbostic 
83346366Sbostic 	if ( new_bucket > hashp->HIGH_MASK ) {
83446366Sbostic 	    /* Starting a new doubling */
83546366Sbostic 	    hashp->LOW_MASK = hashp->HIGH_MASK;
83646366Sbostic 	    hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
83746366Sbostic 	}
83846366Sbostic 
83946366Sbostic 	/*
84046366Sbostic 	 * Relocate records to the new bucket
84146366Sbostic 	 */
84246366Sbostic 	return(__split_page ( old_bucket, new_bucket ));
84346366Sbostic }
84446366Sbostic /*
84546366Sbostic     If realloc guarantees that the pointer is not destroyed
84646366Sbostic     if the realloc fails, then this routine can go away
84746366Sbostic */
84846366Sbostic static char *
84946366Sbostic hash_realloc ( p_ptr, oldsize, newsize )
85046366Sbostic char	**p_ptr;
85146366Sbostic int	oldsize;
85246366Sbostic int	newsize;
85346366Sbostic {
85446366Sbostic 	register char	*p;
85546366Sbostic 
85646366Sbostic 	if (p = (char *)malloc ( newsize ) ) {
85746366Sbostic 		bcopy ( *p_ptr, p, oldsize );
85846366Sbostic 		bzero ( *p_ptr + oldsize, newsize-oldsize );
85946366Sbostic 		free(*p_ptr);
86046366Sbostic 		*p_ptr = p;
86146366Sbostic 	}
86246366Sbostic 	return (p);
86346366Sbostic }
86446366Sbostic 
86546366Sbostic extern int
86646366Sbostic __call_hash ( k, len )
86746366Sbostic char	*k;
86846366Sbostic int	len;
86946366Sbostic {
87046366Sbostic 	int	n, bucket;
87146366Sbostic 	n = hashp->hash(k, len);
87246366Sbostic 
87346366Sbostic 	bucket = n & hashp->HIGH_MASK;
87446366Sbostic 	if ( bucket > hashp->MAX_BUCKET ) {
87546366Sbostic 	    bucket = bucket & hashp->LOW_MASK;
87646366Sbostic 	}
87746366Sbostic 
87846366Sbostic 	return(bucket);
87946366Sbostic }
88046366Sbostic 
88146366Sbostic /*
88246366Sbostic     Allocate segment table.  On error, destroy the table
88346366Sbostic     and set errno.
88446366Sbostic 
88546366Sbostic     Returns 0 on success
88646366Sbostic */
88746366Sbostic static int
88846366Sbostic alloc_segs ( nsegs )
88946366Sbostic int	nsegs;
89046366Sbostic {
89146366Sbostic     register int	i;
89246366Sbostic     register SEGMENT	store;
89346366Sbostic 
89446366Sbostic     int	save_errno;
89546366Sbostic 
89646366Sbostic     if (!(hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
89746366Sbostic 	save_errno = errno;
89846366Sbostic 	(void)hdestroy();
89946366Sbostic 	errno = save_errno;
90046366Sbostic 	return(-1);
90146366Sbostic     }
90246366Sbostic 
90346366Sbostic     /* Allocate segments */
90446366Sbostic     store = (SEGMENT)calloc ( nsegs << hashp->SSHIFT, sizeof (SEGMENT) );
90546366Sbostic     if ( !store ) {
90646366Sbostic 	save_errno = errno;
90746366Sbostic 	(void)hdestroy();
90846366Sbostic 	errno = save_errno;
90946366Sbostic 	return(-1);
91046366Sbostic     }
91146366Sbostic 
91246366Sbostic     for ( i=0; i < nsegs; i++, hashp->nsegs++ ) {
91346366Sbostic 	hashp->dir[i] = &store[i<<hashp->SSHIFT];
91446366Sbostic     }
91546366Sbostic     return(0);
91646366Sbostic }
91746366Sbostic 
91846366Sbostic /*
91946366Sbostic     Hashp->hdr needs to be byteswapped.
92046366Sbostic */
92146366Sbostic static void
92246366Sbostic swap_header_copy ( srcp, destp )
92346366Sbostic HASHHDR	*srcp;
92446366Sbostic HASHHDR	*destp;
92546366Sbostic {
92646366Sbostic     int i;
92746366Sbostic 
92846366Sbostic     BLSWAP_COPY(srcp->magic, destp->magic);
92946366Sbostic     BLSWAP_COPY(srcp->version, destp->version);
93046366Sbostic     BLSWAP_COPY(srcp->lorder, destp->lorder);
93146366Sbostic     BLSWAP_COPY(srcp->bsize, destp->bsize);
93246366Sbostic     BLSWAP_COPY(srcp->bshift, destp->bshift);
93346366Sbostic     BLSWAP_COPY(srcp->dsize, destp->dsize);
93446366Sbostic     BLSWAP_COPY(srcp->ssize, destp->ssize);
93546366Sbostic     BLSWAP_COPY(srcp->sshift, destp->sshift);
93646366Sbostic     BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
93746366Sbostic     BLSWAP_COPY(srcp->high_mask, destp->high_mask);
93846366Sbostic     BLSWAP_COPY(srcp->low_mask, destp->low_mask);
93946366Sbostic     BLSWAP_COPY(srcp->ffactor, destp->ffactor);
94046366Sbostic     BLSWAP_COPY(srcp->nkeys, destp->nkeys);
94146366Sbostic     BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
94246366Sbostic     BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
94346366Sbostic     for ( i=0; i < NCACHED; i++ ) {
94446366Sbostic 	BLSWAP_COPY ( srcp->spares[i] , destp->spares[i]);
94546366Sbostic 	BSSWAP_COPY ( srcp->bitmaps[i] , destp->bitmaps[i]);
94646366Sbostic     }
94746366Sbostic     return;
94846366Sbostic }
94946366Sbostic 
95046366Sbostic static void
95146366Sbostic swap_header ( )
95246366Sbostic {
95346366Sbostic     HASHHDR	*hdrp;
95446366Sbostic     int	i;
95546366Sbostic 
95646366Sbostic     hdrp = &hashp->hdr;
95746366Sbostic 
95846366Sbostic     BLSWAP(hdrp->magic);
95946366Sbostic     BLSWAP(hdrp->version);
96046366Sbostic     BLSWAP(hdrp->lorder);
96146366Sbostic     BLSWAP(hdrp->bsize);
96246366Sbostic     BLSWAP(hdrp->bshift);
96346366Sbostic     BLSWAP(hdrp->dsize);
96446366Sbostic     BLSWAP(hdrp->ssize);
96546366Sbostic     BLSWAP(hdrp->sshift);
96646366Sbostic     BLSWAP(hdrp->max_bucket);
96746366Sbostic     BLSWAP(hdrp->high_mask);
96846366Sbostic     BLSWAP(hdrp->low_mask);
96946366Sbostic     BLSWAP(hdrp->ffactor);
97046366Sbostic     BLSWAP(hdrp->nkeys);
97146366Sbostic     BLSWAP(hdrp->hdrpages);
97246366Sbostic     BLSWAP(hdrp->h_charkey);
97346366Sbostic     for ( i=0; i < NCACHED; i++ ) {
97446366Sbostic 	BLSWAP ( hdrp->spares[i] );
97546366Sbostic 	BSSWAP ( hdrp->bitmaps[i] );
97646366Sbostic     }
97746366Sbostic     return;
97846366Sbostic }
979