xref: /csrg-svn/lib/libc/db/hash/hash.c (revision 58016)
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*58016Sbostic static char sccsid[] = "@(#)hash.c	5.32 (Berkeley) 02/16/93";
1346366Sbostic #endif /* LIBC_SCCS and not lint */
1446366Sbostic 
1546366Sbostic #include <sys/param.h>
1646366Sbostic #include <sys/stat.h>
1755452Sbostic 
1857586Sbostic #include <errno.h>
1946562Sbostic #include <fcntl.h>
2057586Sbostic #include <stdio.h>
2157586Sbostic #include <stdlib.h>
2257586Sbostic #include <string.h>
2357586Sbostic #include <unistd.h>
2450997Sbostic #ifdef DEBUG
2546366Sbostic #include <assert.h>
2650997Sbostic #endif
2757586Sbostic 
2857932Sbostic #include <db.h>
2946366Sbostic #include "hash.h"
3050997Sbostic #include "page.h"
3150997Sbostic #include "extern.h"
3246366Sbostic 
3357586Sbostic static int   alloc_segs __P((HTAB *, int));
3457586Sbostic static int   flush_meta __P((HTAB *));
3557586Sbostic static int   hash_access __P((HTAB *, ACTION, DBT *, DBT *));
3650997Sbostic static int   hash_close __P((DB *));
3750997Sbostic static int   hash_delete __P((const DB *, const DBT *, u_int));
3851057Sbostic static int   hash_get __P((const DB *, const DBT *, DBT *, u_int));
3956893Sbostic static int   hash_put __P((const DB *, DBT *, const DBT *, u_int));
4050997Sbostic static void *hash_realloc __P((SEGMENT **, int, int));
4150997Sbostic static int   hash_seq __P((const DB *, DBT *, DBT *, u_int));
4250997Sbostic static int   hash_sync __P((const DB *));
4357586Sbostic static int   hdestroy __P((HTAB *));
4457586Sbostic static HTAB *init_hash __P((HTAB *, HASHINFO *));
4557586Sbostic static int   init_htab __P((HTAB *, int));
4650997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
4757586Sbostic static void  swap_header __P((HTAB *, void));
4850997Sbostic static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
4950997Sbostic #endif
5050997Sbostic 
5146366Sbostic /* Fast arithmetic, relying on powers of 2, */
5250997Sbostic #define MOD(x, y)		((x) & ((y) - 1))
5346366Sbostic 
5450997Sbostic #define RETURN_ERROR(ERR, LOC)	{ save_errno = ERR; goto LOC; }
5546366Sbostic 
5646366Sbostic /* Return values */
5750997Sbostic #define	SUCCESS	 (0)
5850997Sbostic #define	ERROR	(-1)
5950997Sbostic #define	ABNORMAL (1)
6046366Sbostic 
6146366Sbostic #ifdef HASH_STATISTICS
6246366Sbostic long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
6346366Sbostic #endif
6446366Sbostic 
6550997Sbostic /************************** INTERFACE ROUTINES ***************************/
6646366Sbostic /* OPEN/CLOSE */
6746366Sbostic 
6850997Sbostic extern DB *
6951072Sbostic __hash_open(file, flags, mode, info)
7050997Sbostic 	const char *file;
7150997Sbostic 	int flags, mode;
7250997Sbostic 	const HASHINFO *info;	/* Special directives for create */
7346366Sbostic {
7457586Sbostic 	HTAB *hashp;
7550997Sbostic 	struct stat statbuf;
7650997Sbostic 	DB *dbp;
7750997Sbostic 	int bpages, hdrsize, new_table, nsegs, save_errno;
7846366Sbostic 
7956661Sbostic 	if ((flags & O_ACCMODE) == O_WRONLY) {
8056422Smargo 		errno = EINVAL;
8156422Smargo 		return (NULL);
8256422Smargo 	}
8356422Smargo 
8450997Sbostic 	if (!(hashp = calloc(1, sizeof(HTAB))))
8550997Sbostic 		return (NULL);
8650997Sbostic 	hashp->fp = -1;
8750997Sbostic 	/*
8850997Sbostic 	 * Select flags relevant to us. Even if user wants write only, we need
8950997Sbostic 	 * to be able to read the actual file, so we need to open it read/write.
9050997Sbostic 	 * But, the field in the hashp structure needs to be accurate so that
9150997Sbostic 	 * we can check accesses.
9250997Sbostic 	 */
9356893Sbostic 	hashp->flags = flags = flags & __USE_OPEN_FLAGS;
9446366Sbostic 
9550997Sbostic 	new_table = 0;
9650997Sbostic 	if (!file || (flags & O_TRUNC) ||
9750997Sbostic 	    (stat(file, &statbuf) && (errno == ENOENT))) {
9850997Sbostic 		if (errno == ENOENT)
9950997Sbostic 			errno = 0; /* Just in case someone looks at errno */
10050997Sbostic 		new_table = 1;
10146485Sbostic 	}
10250997Sbostic 	if (file) {
10350997Sbostic 		if ((hashp->fp = open(file, flags, mode)) == -1)
10450997Sbostic 			RETURN_ERROR(errno, error0);
10550997Sbostic 		(void)fcntl(hashp->fp, F_SETFD, 1);
10646366Sbostic 	}
10750997Sbostic 	if (new_table) {
10857586Sbostic 		if (!(hashp = init_hash(hashp, (HASHINFO *)info)))
10950997Sbostic 			RETURN_ERROR(errno, error1);
11050997Sbostic 	} else {
11150997Sbostic 		/* Table already exists */
11250997Sbostic 		if (info && info->hash)
11350997Sbostic 			hashp->hash = info->hash;
11450997Sbostic 		else
11557586Sbostic 			hashp->hash = __default_hash;
11646366Sbostic 
11750997Sbostic 		hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
11846366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
11957586Sbostic 		swap_header(hashp);
12046366Sbostic #endif
12150997Sbostic 		if (hdrsize == -1)
12250997Sbostic 			RETURN_ERROR(errno, error1);
12350997Sbostic 		if (hdrsize != sizeof(HASHHDR))
12450997Sbostic 			RETURN_ERROR(EFTYPE, error1);
12550997Sbostic 		/* Verify file type, versions and hash function */
12650997Sbostic 		if (hashp->MAGIC != HASHMAGIC)
12750997Sbostic 			RETURN_ERROR(EFTYPE, error1);
12851061Sbostic 		if (hashp->VERSION != HASHVERSION)
12950997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13050997Sbostic 		if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
13150997Sbostic 			RETURN_ERROR(EFTYPE, error1);
13251057Sbostic 		/*
13351057Sbostic 		 * Figure out how many segments we need.  Max_Bucket is the
13451057Sbostic 		 * maximum bucket number, so the number of buckets is
13551057Sbostic 		 * max_bucket + 1.
13651057Sbostic 		 */
13751057Sbostic 		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
13850997Sbostic 			 hashp->SGSIZE;
13950997Sbostic 		hashp->nsegs = 0;
14057586Sbostic 		if (alloc_segs(hashp, nsegs))
14150997Sbostic 			/*
14250997Sbostic 			 * If alloc_segs fails, table will have been destroyed
14350997Sbostic 			 * and errno will have been set.
14450997Sbostic 			 */
14550997Sbostic 			return (NULL);
14650997Sbostic 		/* Read in bitmaps */
14751061Sbostic 		bpages = (hashp->SPARES[hashp->OVFL_POINT] +
14850997Sbostic 		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>
14950997Sbostic 		    (hashp->BSHIFT + BYTE_SHIFT);
15046366Sbostic 
15150997Sbostic 		hashp->nmaps = bpages;
15251057Sbostic 		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_long *));
15346366Sbostic 	}
15446366Sbostic 
15550997Sbostic 	/* Initialize Buffer Manager */
15650997Sbostic 	if (info && info->cachesize)
15757586Sbostic 		__buf_init(hashp, info->cachesize);
15850997Sbostic 	else
15957586Sbostic 		__buf_init(hashp, DEF_BUFSIZE);
16050997Sbostic 
16150997Sbostic 	hashp->new_file = new_table;
16256422Smargo 	hashp->save_file = file && (hashp->flags & O_RDWR);
16350997Sbostic 	hashp->cbucket = -1;
16450997Sbostic 	if (!(dbp = malloc(sizeof(DB)))) {
16550997Sbostic 		save_errno = errno;
16657586Sbostic 		hdestroy(hashp);
16750997Sbostic 		errno = save_errno;
16850997Sbostic 		return (NULL);
16946366Sbostic 	}
17057586Sbostic 	dbp->internal = hashp;
17150997Sbostic 	dbp->close = hash_close;
17250997Sbostic 	dbp->del = hash_delete;
17350997Sbostic 	dbp->get = hash_get;
17450997Sbostic 	dbp->put = hash_put;
17550997Sbostic 	dbp->seq = hash_seq;
17650997Sbostic 	dbp->sync = hash_sync;
17750997Sbostic 	dbp->type = DB_HASH;
17846366Sbostic 
17946366Sbostic #ifdef DEBUG
18050997Sbostic 	(void)fprintf(stderr,
18151061Sbostic "%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%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
18250997Sbostic 	    "init_htab:",
18350997Sbostic 	    "TABLE POINTER   ", hashp,
18450997Sbostic 	    "BUCKET SIZE     ", hashp->BSIZE,
18550997Sbostic 	    "BUCKET SHIFT    ", hashp->BSHIFT,
18650997Sbostic 	    "DIRECTORY SIZE  ", hashp->DSIZE,
18750997Sbostic 	    "SEGMENT SIZE    ", hashp->SGSIZE,
18850997Sbostic 	    "SEGMENT SHIFT   ", hashp->SSHIFT,
18950997Sbostic 	    "FILL FACTOR     ", hashp->FFACTOR,
19050997Sbostic 	    "MAX BUCKET      ", hashp->MAX_BUCKET,
19151061Sbostic 	    "OVFL POINT	     ", hashp->OVFL_POINT,
19251061Sbostic 	    "LAST FREED      ", hashp->LAST_FREED,
19350997Sbostic 	    "HIGH MASK       ", hashp->HIGH_MASK,
19450997Sbostic 	    "LOW  MASK       ", hashp->LOW_MASK,
19550997Sbostic 	    "NSEGS           ", hashp->nsegs,
19650997Sbostic 	    "NKEYS           ", hashp->NKEYS);
19746366Sbostic #endif
19846366Sbostic #ifdef HASH_STATISTICS
19946366Sbostic 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
20046366Sbostic #endif
20150997Sbostic 	return (dbp);
20246366Sbostic 
20346366Sbostic error1:
20451192Sbostic 	if (hashp != NULL)
20551192Sbostic 		(void)close(hashp->fp);
20646366Sbostic 
20746366Sbostic error0:
20850997Sbostic 	free(hashp);
20950997Sbostic 	errno = save_errno;
21050997Sbostic 	return (NULL);
21146366Sbostic }
21246366Sbostic 
21346366Sbostic static int
21450997Sbostic hash_close(dbp)
21550997Sbostic 	DB *dbp;
21646366Sbostic {
21757586Sbostic 	HTAB *hashp;
21850997Sbostic 	int retval;
21946457Sbostic 
22050997Sbostic 	if (!dbp)
22150997Sbostic 		return (ERROR);
22257586Sbostic 
22346366Sbostic 	hashp = (HTAB *)dbp->internal;
22457586Sbostic 	retval = hdestroy(hashp);
22550997Sbostic 	free(dbp);
22650997Sbostic 	return (retval);
22746366Sbostic }
22846366Sbostic 
22946366Sbostic /************************** LOCAL CREATION ROUTINES **********************/
23050997Sbostic static HTAB *
23157586Sbostic init_hash(hashp, info)
23257586Sbostic 	HTAB *hashp;
23350997Sbostic 	HASHINFO *info;
23446366Sbostic {
23550997Sbostic 	int nelem;
23646366Sbostic 
23746366Sbostic 	nelem = 1;
23851061Sbostic 	hashp->NKEYS = 0;
23950997Sbostic 	hashp->LORDER = BYTE_ORDER;
24050997Sbostic 	hashp->BSIZE = DEF_BUCKET_SIZE;
24150997Sbostic 	hashp->BSHIFT = DEF_BUCKET_SHIFT;
24250997Sbostic 	hashp->SGSIZE = DEF_SEGSIZE;
24350997Sbostic 	hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
24450997Sbostic 	hashp->DSIZE = DEF_DIRSIZE;
24550997Sbostic 	hashp->FFACTOR = DEF_FFACTOR;
24657586Sbostic 	hashp->hash = __default_hash;
247*58016Sbostic 	memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
248*58016Sbostic 	memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
24946366Sbostic 
25050997Sbostic 	if (info) {
25150997Sbostic 		if (info->bsize) {
25250997Sbostic 			/* Round pagesize up to power of 2 */
25350997Sbostic 			hashp->BSHIFT = __log2(info->bsize);
25450997Sbostic 			hashp->BSIZE = 1 << hashp->BSHIFT;
25550997Sbostic 			if (hashp->BSIZE > MAX_BSIZE) {
25650997Sbostic 				errno = EINVAL;
25750997Sbostic 				return (NULL);
25850997Sbostic 			}
25946366Sbostic 		}
26050997Sbostic 		if (info->ffactor)
26150997Sbostic 			hashp->FFACTOR = info->ffactor;
26250997Sbostic 		if (info->hash)
26350997Sbostic 			hashp->hash = info->hash;
26450997Sbostic 		if (info->nelem)
26550997Sbostic 			nelem = info->nelem;
26650997Sbostic 		if (info->lorder) {
26750997Sbostic 			if (info->lorder != BIG_ENDIAN &&
26850997Sbostic 			    info->lorder != LITTLE_ENDIAN) {
26950997Sbostic 				errno = EINVAL;
27050997Sbostic 				return (NULL);
27150997Sbostic 			}
27250997Sbostic 			hashp->LORDER = info->lorder;
27346366Sbostic 		}
27446366Sbostic 	}
27546366Sbostic 	/* init_htab should destroy the table and set errno if it fails */
27657586Sbostic 	if (init_htab(hashp, nelem))
27750997Sbostic 		return (NULL);
27850997Sbostic 	else
27950997Sbostic 		return (hashp);
28046366Sbostic }
28146366Sbostic /*
28250997Sbostic  * This calls alloc_segs which may run out of memory.  Alloc_segs will destroy
28350997Sbostic  * the table and set errno, so we just pass the error information along.
28450997Sbostic  *
28550997Sbostic  * Returns 0 on No Error
28650997Sbostic  */
28746366Sbostic static int
28857586Sbostic init_htab(hashp, nelem)
28957586Sbostic 	HTAB *hashp;
29050997Sbostic 	int nelem;
29146366Sbostic {
29250997Sbostic 	register int nbuckets, nsegs;
29350997Sbostic 	int l2;
29446366Sbostic 
29550997Sbostic 	/*
29650997Sbostic 	 * Divide number of elements by the fill factor and determine a
29750997Sbostic 	 * desired number of buckets.  Allocate space for the next greater
29850997Sbostic 	 * power of two number of buckets.
29950997Sbostic 	 */
30046366Sbostic 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
30146366Sbostic 
30252001Sbostic 	l2 = __log2(MAX(nelem, 2));
30346366Sbostic 	nbuckets = 1 << l2;
30446366Sbostic 
30546366Sbostic 	hashp->SPARES[l2] = l2 + 1;
30650997Sbostic 	hashp->SPARES[l2 + 1] = l2 + 1;
30751061Sbostic 	hashp->OVFL_POINT = l2;
30851061Sbostic 	hashp->LAST_FREED = 2;
30951061Sbostic 
31050997Sbostic 	/* First bitmap page is at: splitpoint l2 page offset 1 */
31157586Sbostic 	if (__init_bitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
31251057Sbostic 		return (-1);
31346366Sbostic 
31446366Sbostic 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
31546366Sbostic 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
31650997Sbostic 	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
31750997Sbostic 	    hashp->BSHIFT) + 1;
31846366Sbostic 
31946366Sbostic 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
32046366Sbostic 	nsegs = 1 << __log2(nsegs);
32146366Sbostic 
32250997Sbostic 	if (nsegs > hashp->DSIZE)
32350997Sbostic 		hashp->DSIZE = nsegs;
32457586Sbostic 	return (alloc_segs(hashp, nsegs));
32546366Sbostic }
32646366Sbostic 
32746366Sbostic /********************** DESTROY/CLOSE ROUTINES ************************/
32846366Sbostic 
32946366Sbostic /*
33050997Sbostic  * Flushes any changes to the file if necessary and destroys the hashp
33150997Sbostic  * structure, freeing all allocated space.
33250997Sbostic  */
33346366Sbostic static int
33457586Sbostic hdestroy(hashp)
33557586Sbostic 	HTAB *hashp;
33646366Sbostic {
33750997Sbostic 	int i, save_errno;
33846366Sbostic 
33946366Sbostic 	save_errno = 0;
34046366Sbostic 
34146366Sbostic #ifdef HASH_STATISTICS
34257586Sbostic 	(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
34357586Sbostic 	    hash_accesses, hash_collisions);
34457586Sbostic 	(void)fprintf(stderr, "hdestroy: expansions %ld\n",
34557586Sbostic 	    hash_expansions);
34657586Sbostic 	(void)fprintf(stderr, "hdestroy: overflows %ld\n",
34757586Sbostic 	    hash_overflows);
34857586Sbostic 	(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
34957586Sbostic 	    hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
35046366Sbostic 
35157586Sbostic 	for (i = 0; i < NCACHED; i++)
35257586Sbostic 		(void)fprintf(stderr,
35357586Sbostic 		    "spares[%d] = %d\n", i, hashp->SPARES[i]);
35446366Sbostic #endif
35557586Sbostic 	/*
35657586Sbostic 	 * Call on buffer manager to free buffers, and if required,
35757586Sbostic 	 * write them to disk.
35857586Sbostic 	 */
35957586Sbostic 	if (__buf_free(hashp, 1, hashp->save_file))
36057586Sbostic 		save_errno = errno;
36157586Sbostic 	if (hashp->dir) {
36257586Sbostic 		free(*hashp->dir);	/* Free initial segments */
36357586Sbostic 		/* Free extra segments */
36457586Sbostic 		while (hashp->exsegs--)
36557586Sbostic 			free(hashp->dir[--hashp->nsegs]);
36657586Sbostic 		free(hashp->dir);
36757586Sbostic 	}
36857586Sbostic 	if (flush_meta(hashp) && !save_errno)
36957586Sbostic 		save_errno = errno;
37057586Sbostic 	/* Free Bigmaps */
37157586Sbostic 	for (i = 0; i < hashp->nmaps; i++)
37257586Sbostic 		if (hashp->mapp[i])
37357586Sbostic 			free(hashp->mapp[i]);
37446503Sbostic 
37557586Sbostic 	if (hashp->fp != -1)
37657586Sbostic 		(void)close(hashp->fp);
37757586Sbostic 
37850997Sbostic 	if (save_errno) {
37950997Sbostic 		errno = save_errno;
38050997Sbostic 		return (ERROR);
38146366Sbostic 	}
38250997Sbostic 	return (SUCCESS);
38346366Sbostic }
38450997Sbostic /*
38550997Sbostic  * Write modified pages to disk
38650997Sbostic  *
38750997Sbostic  * Returns:
38850997Sbostic  *	 0 == OK
38950997Sbostic  *	-1 ERROR
39050997Sbostic  */
39146366Sbostic static int
39246366Sbostic hash_sync(dbp)
39350997Sbostic 	const DB *dbp;
39446366Sbostic {
39557586Sbostic 	HTAB *hashp;
39657586Sbostic 
39750997Sbostic 	if (!dbp)
39850997Sbostic 		return (ERROR);
39957586Sbostic 
40046366Sbostic 	hashp = (HTAB *)dbp->internal;
40150997Sbostic 	if (!hashp->save_file)
40250997Sbostic 		return (0);
40357586Sbostic 	if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
40450997Sbostic 		return (ERROR);
40546366Sbostic 	hashp->new_file = 0;
40650997Sbostic 	return (0);
40746366Sbostic }
40846366Sbostic 
40946366Sbostic /*
41050997Sbostic  * Returns:
41150997Sbostic  *	 0 == OK
41250997Sbostic  *	-1 indicates that errno should be set
41350997Sbostic  */
41446366Sbostic static int
41557586Sbostic flush_meta(hashp)
41657586Sbostic 	HTAB *hashp;
41746366Sbostic {
41851814Smarc 	HASHHDR *whdrp;
41951814Smarc #if BYTE_ORDER == LITTLE_ENDIAN
42051814Smarc 	HASHHDR whdr;
42151814Smarc #endif
42250997Sbostic 	int fp, i, wsize;
42346366Sbostic 
42450997Sbostic 	if (!hashp->save_file)
42550997Sbostic 		return (0);
42646366Sbostic 	hashp->MAGIC = HASHMAGIC;
42751061Sbostic 	hashp->VERSION = HASHVERSION;
42850997Sbostic 	hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
42946366Sbostic 
43046366Sbostic 	fp = hashp->fp;
43146366Sbostic 	whdrp = &hashp->hdr;
43246366Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
43346366Sbostic 	whdrp = &whdr;
43450997Sbostic 	swap_header_copy(&hashp->hdr, whdrp);
43546366Sbostic #endif
43656669Sbostic 	if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
43750997Sbostic 	    ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
43850997Sbostic 		return (-1);
43950997Sbostic 	else
44050997Sbostic 		if (wsize != sizeof(HASHHDR)) {
44150997Sbostic 			errno = EFTYPE;
44250997Sbostic 			hashp->errno = errno;
44350997Sbostic 			return (-1);
44446366Sbostic 		}
44550997Sbostic 	for (i = 0; i < NCACHED; i++)
44650997Sbostic 		if (hashp->mapp[i])
44757586Sbostic 			if (__put_page(hashp, (char *)hashp->mapp[i],
44850997Sbostic 				hashp->BITMAPS[i], 0, 1))
44950997Sbostic 				return (-1);
45050997Sbostic 	return (0);
45146366Sbostic }
45250997Sbostic 
45346366Sbostic /*******************************SEARCH ROUTINES *****************************/
45446366Sbostic /*
45550997Sbostic  * All the access routines return
45650997Sbostic  *
45750997Sbostic  * Returns:
45850997Sbostic  *	 0 on SUCCESS
45950997Sbostic  *	 1 to indicate an external ERROR (i.e. key not found, etc)
46050997Sbostic  *	-1 to indicate an internal ERROR (i.e. out of memory, etc)
46150997Sbostic  */
46246366Sbostic static int
46350997Sbostic hash_get(dbp, key, data, flag)
46450997Sbostic 	const DB *dbp;
46551057Sbostic 	const DBT *key;
46651057Sbostic 	DBT *data;
46750997Sbostic 	u_int flag;
46846366Sbostic {
46957586Sbostic 	HTAB *hashp;
47057586Sbostic 
47157586Sbostic 	hashp = (HTAB *)dbp->internal;
47250997Sbostic 	if (flag) {
47350997Sbostic 		hashp->errno = errno = EINVAL;
47450997Sbostic 		return (ERROR);
47550997Sbostic 	}
47657586Sbostic 	return (hash_access(hashp, HASH_GET, (DBT *)key, data));
47746366Sbostic }
47846366Sbostic 
47946366Sbostic static int
48050997Sbostic hash_put(dbp, key, data, flag)
48150997Sbostic 	const DB *dbp;
48256893Sbostic 	DBT *key;
48356893Sbostic 	const DBT *data;
48450997Sbostic 	u_int flag;
48546366Sbostic {
48657586Sbostic 	HTAB *hashp;
48757586Sbostic 
48857586Sbostic 	hashp = (HTAB *)dbp->internal;
48950997Sbostic 	if (flag && flag != R_NOOVERWRITE) {
49050997Sbostic 		hashp->errno = errno = EINVAL;
49150997Sbostic 		return (ERROR);
49250997Sbostic 	}
49350997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
49450997Sbostic 		hashp->errno = errno = EPERM;
49550997Sbostic 		return (ERROR);
49650997Sbostic 	}
49757586Sbostic 	return (hash_access(hashp, flag == R_NOOVERWRITE ?
49850997Sbostic 	    HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
49946366Sbostic }
50046366Sbostic 
50146366Sbostic static int
50250997Sbostic hash_delete(dbp, key, flag)
50350997Sbostic 	const DB *dbp;
50450997Sbostic 	const DBT *key;
50550997Sbostic 	u_int flag;		/* Ignored */
50646366Sbostic {
50757586Sbostic 	HTAB *hashp;
50857586Sbostic 
50957586Sbostic 	hashp = (HTAB *)dbp->internal;
51050997Sbostic 	if (flag && flag != R_CURSOR) {
51150997Sbostic 		hashp->errno = errno = EINVAL;
51250997Sbostic 		return (ERROR);
51350997Sbostic 	}
51450997Sbostic 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
51550997Sbostic 		hashp->errno = errno = EPERM;
51650997Sbostic 		return (ERROR);
51750997Sbostic 	}
51857586Sbostic 	return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
51946366Sbostic }
52046366Sbostic 
52146366Sbostic /*
52250997Sbostic  * Assume that hashp has been set in wrapper routine.
52350997Sbostic  */
52446366Sbostic static int
52557586Sbostic hash_access(hashp, action, key, val)
52657586Sbostic 	HTAB *hashp;
52750997Sbostic 	ACTION action;
52850997Sbostic 	DBT *key, *val;
52946366Sbostic {
53050997Sbostic 	register BUFHEAD *rbufp;
53150997Sbostic 	BUFHEAD *bufp, *save_bufp;
53250997Sbostic 	register u_short *bp;
53350997Sbostic 	register int n, ndx, off, size;
53450997Sbostic 	register char *kp;
53550997Sbostic 	u_short pageno;
53646366Sbostic 
53746366Sbostic #ifdef HASH_STATISTICS
53846366Sbostic 	hash_accesses++;
53946366Sbostic #endif
54046366Sbostic 
54150997Sbostic 	off = hashp->BSIZE;
54246366Sbostic 	size = key->size;
54346950Sbostic 	kp = (char *)key->data;
54457586Sbostic 	rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
54550997Sbostic 	if (!rbufp)
54650997Sbostic 		return (ERROR);
54746457Sbostic 	save_bufp = rbufp;
54846366Sbostic 
54946457Sbostic 	/* Pin the bucket chain */
55046457Sbostic 	rbufp->flags |= BUF_PIN;
55150997Sbostic 	for (bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
55250997Sbostic 		if (bp[1] >= REAL_KEY) {
55350997Sbostic 			/* Real key/data pair */
55450997Sbostic 			if (size == off - *bp &&
555*58016Sbostic 			    memcmp(kp, rbufp->page + *bp, size) == 0)
55650997Sbostic 				goto found;
55750997Sbostic 			off = bp[1];
55846366Sbostic #ifdef HASH_STATISTICS
55950997Sbostic 			hash_collisions++;
56046366Sbostic #endif
56150997Sbostic 			bp += 2;
56250997Sbostic 			ndx += 2;
56350997Sbostic 		} else if (bp[1] == OVFLPAGE) {
56457586Sbostic 			rbufp = __get_buf(hashp, *bp, rbufp, 0);
56550997Sbostic 			if (!rbufp) {
56650997Sbostic 				save_bufp->flags &= ~BUF_PIN;
56750997Sbostic 				return (ERROR);
56850997Sbostic 			}
56950997Sbostic 			/* FOR LOOP INIT */
57050997Sbostic 			bp = (u_short *)rbufp->page;
57150997Sbostic 			n = *bp++;
57250997Sbostic 			ndx = 1;
57350997Sbostic 			off = hashp->BSIZE;
57450997Sbostic 		} else if (bp[1] < REAL_KEY) {
57557586Sbostic 			if ((ndx =
57657586Sbostic 			    __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
57750997Sbostic 				goto found;
57850997Sbostic 			if (ndx == -2) {
57950997Sbostic 				bufp = rbufp;
58057586Sbostic 				if (!(pageno =
58157586Sbostic 				    __find_last_page(hashp, &bufp))) {
58250997Sbostic 					ndx = 0;
58350997Sbostic 					rbufp = bufp;
58450997Sbostic 					break;	/* FOR */
58550997Sbostic 				}
58657586Sbostic 				rbufp = __get_buf(hashp, pageno, bufp, 0);
58750997Sbostic 				if (!rbufp) {
58850997Sbostic 					save_bufp->flags &= ~BUF_PIN;
58950997Sbostic 					return (ERROR);
59050997Sbostic 				}
59150997Sbostic 				/* FOR LOOP INIT */
59250997Sbostic 				bp = (u_short *)rbufp->page;
59350997Sbostic 				n = *bp++;
59450997Sbostic 				ndx = 1;
59550997Sbostic 				off = hashp->BSIZE;
59650997Sbostic 			} else {
59750997Sbostic 				save_bufp->flags &= ~BUF_PIN;
59850997Sbostic 				return (ERROR);
59950997Sbostic 			}
60046457Sbostic 		}
60146366Sbostic 
60246366Sbostic 	/* Not found */
60350997Sbostic 	switch (action) {
60450997Sbostic 	case HASH_PUT:
60550997Sbostic 	case HASH_PUTNEW:
60657586Sbostic 		if (__addel(hashp, rbufp, key, val)) {
60750997Sbostic 			save_bufp->flags &= ~BUF_PIN;
60850997Sbostic 			return (ERROR);
60946366Sbostic 		} else {
61050997Sbostic 			save_bufp->flags &= ~BUF_PIN;
61150997Sbostic 			return (SUCCESS);
61246366Sbostic 		}
61350997Sbostic 	case HASH_GET:
61450997Sbostic 	case HASH_DELETE:
61550997Sbostic 	default:
61646457Sbostic 		save_bufp->flags &= ~BUF_PIN;
61750997Sbostic 		return (ABNORMAL);
61846366Sbostic 	}
61946366Sbostic 
62046366Sbostic found:
62146366Sbostic 	switch (action) {
62250997Sbostic 	case HASH_PUTNEW:
62346457Sbostic 		save_bufp->flags &= ~BUF_PIN;
62450997Sbostic 		return (ABNORMAL);
62550997Sbostic 	case HASH_GET:
62646366Sbostic 		bp = (u_short *)rbufp->page;
62751072Sbostic 		if (bp[ndx + 1] < REAL_KEY) {
62857586Sbostic 			if (__big_return(hashp, rbufp, ndx, val, 0))
62951057Sbostic 				return (ERROR);
63051072Sbostic 		} else {
63150997Sbostic 			val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
63250997Sbostic 			val->size = bp[ndx] - bp[ndx + 1];
63346366Sbostic 		}
63446366Sbostic 		break;
63550997Sbostic 	case HASH_PUT:
63657586Sbostic 		if ((__delpair(hashp, rbufp, ndx)) ||
63757586Sbostic 		    (__addel(hashp, rbufp, key, val))) {
63850997Sbostic 			save_bufp->flags &= ~BUF_PIN;
63950997Sbostic 			return (ERROR);
64046457Sbostic 		}
64146366Sbostic 		break;
64250997Sbostic 	case HASH_DELETE:
64357586Sbostic 		if (__delpair(hashp, rbufp, ndx))
64450997Sbostic 			return (ERROR);
64546366Sbostic 		break;
64657586Sbostic 	default:
64757586Sbostic 		abort();
64846366Sbostic 	}
64946457Sbostic 	save_bufp->flags &= ~BUF_PIN;
65046366Sbostic 	return (SUCCESS);
65146366Sbostic }
65246366Sbostic 
65346366Sbostic static int
65446366Sbostic hash_seq(dbp, key, data, flag)
65550997Sbostic 	const DB *dbp;
65650997Sbostic 	DBT *key, *data;
65750997Sbostic 	u_int flag;
65846366Sbostic {
65950997Sbostic 	register u_int bucket;
66050997Sbostic 	register BUFHEAD *bufp;
66157586Sbostic 	HTAB *hashp;
66250997Sbostic 	u_short *bp, ndx;
66346366Sbostic 
66457586Sbostic 	hashp = (HTAB *)dbp->internal;
66550997Sbostic 	if (flag && flag != R_FIRST && flag != R_NEXT) {
66650997Sbostic 		hashp->errno = errno = EINVAL;
66750997Sbostic 		return (ERROR);
66846366Sbostic 	}
66946366Sbostic #ifdef HASH_STATISTICS
67046366Sbostic 	hash_accesses++;
67146366Sbostic #endif
67250997Sbostic 	if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
67350997Sbostic 		hashp->cbucket = 0;
67450997Sbostic 		hashp->cndx = 1;
67550997Sbostic 		hashp->cpage = NULL;
67646366Sbostic 	}
67746366Sbostic 
67855874Sbostic 	for (bp = NULL; !bp || !bp[0]; ) {
67955452Sbostic 		if (!(bufp = hashp->cpage)) {
68055452Sbostic 			for (bucket = hashp->cbucket;
68155452Sbostic 			    bucket <= hashp->MAX_BUCKET;
68255452Sbostic 			    bucket++, hashp->cndx = 1) {
68357586Sbostic 				bufp = __get_buf(hashp, bucket, NULL, 0);
68455452Sbostic 				if (!bufp)
68555452Sbostic 					return (ERROR);
68655452Sbostic 				hashp->cpage = bufp;
68755452Sbostic 				bp = (u_short *)bufp->page;
68855452Sbostic 				if (bp[0])
68955452Sbostic 					break;
69055452Sbostic 			}
69155452Sbostic 			hashp->cbucket = bucket;
69255452Sbostic 			if (hashp->cbucket > hashp->MAX_BUCKET) {
69355452Sbostic 				hashp->cbucket = -1;
69455452Sbostic 				return (ABNORMAL);
69555452Sbostic 			}
69655452Sbostic 		} else
69755452Sbostic 			bp = (u_short *)hashp->cpage->page;
69855452Sbostic 
69955452Sbostic #ifdef DEBUG
70055452Sbostic 		assert(bp);
70155452Sbostic 		assert(bufp);
70255452Sbostic #endif
70355452Sbostic 		while (bp[hashp->cndx + 1] == OVFLPAGE) {
70455452Sbostic 			bufp = hashp->cpage =
70557586Sbostic 			    __get_buf(hashp, bp[hashp->cndx], bufp, 0);
70650997Sbostic 			if (!bufp)
70750997Sbostic 				return (ERROR);
70855452Sbostic 			bp = (u_short *)(bufp->page);
70955452Sbostic 			hashp->cndx = 1;
71050997Sbostic 		}
71155874Sbostic 		if (!bp[0]) {
71255452Sbostic 			hashp->cpage = NULL;
71355874Sbostic 			++hashp->cbucket;
71455874Sbostic 		}
71546366Sbostic 	}
71646366Sbostic 	ndx = hashp->cndx;
71750997Sbostic 	if (bp[ndx + 1] < REAL_KEY) {
71857586Sbostic 		if (__big_keydata(hashp, bufp, key, data, 1))
71950997Sbostic 			return (ERROR);
72046366Sbostic 	} else {
72150997Sbostic 		key->data = (u_char *)hashp->cpage->page + bp[ndx];
72250997Sbostic 		key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
72350997Sbostic 		data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
72450997Sbostic 		data->size = bp[ndx] - bp[ndx + 1];
72550997Sbostic 		ndx += 2;
72650997Sbostic 		if (ndx > bp[0]) {
72750997Sbostic 			hashp->cpage = NULL;
72850997Sbostic 			hashp->cbucket++;
72950997Sbostic 			hashp->cndx = 1;
73050997Sbostic 		} else
73150997Sbostic 			hashp->cndx = ndx;
73246366Sbostic 	}
73346366Sbostic 	return (SUCCESS);
73446366Sbostic }
73546366Sbostic 
73646366Sbostic /********************************* UTILITIES ************************/
73750997Sbostic 
73846366Sbostic /*
73950997Sbostic  * Returns:
74050997Sbostic  *	 0 ==> OK
74150997Sbostic  *	-1 ==> Error
74250997Sbostic  */
74346366Sbostic extern int
74457586Sbostic __expand_table(hashp)
74557586Sbostic 	HTAB *hashp;
74646366Sbostic {
74750997Sbostic 	u_int old_bucket, new_bucket;
74850997Sbostic 	int dirsize, new_segnum, spare_ndx;
74950997Sbostic 
75046366Sbostic #ifdef HASH_STATISTICS
75146366Sbostic 	hash_expansions++;
75246366Sbostic #endif
75346366Sbostic 	new_bucket = ++hashp->MAX_BUCKET;
75446366Sbostic 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
75546366Sbostic 
75646366Sbostic 	new_segnum = new_bucket >> hashp->SSHIFT;
75746366Sbostic 
75846366Sbostic 	/* Check if we need a new segment */
75950997Sbostic 	if (new_segnum >= hashp->nsegs) {
76050997Sbostic 		/* Check if we need to expand directory */
76150997Sbostic 		if (new_segnum >= hashp->DSIZE) {
76250997Sbostic 			/* Reallocate directory */
76350997Sbostic 			dirsize = hashp->DSIZE * sizeof(SEGMENT *);
76450997Sbostic 			if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
76550997Sbostic 				return (-1);
76650997Sbostic 			hashp->DSIZE = dirsize << 1;
76746366Sbostic 		}
76850997Sbostic 		if (!(hashp->dir[new_segnum] =
76950997Sbostic 			calloc(hashp->SGSIZE, sizeof(SEGMENT))))
77050997Sbostic 			return (-1);
77150997Sbostic 		hashp->exsegs++;
77250997Sbostic 		hashp->nsegs++;
77346366Sbostic 	}
77446366Sbostic 	/*
77550997Sbostic 	 * If the split point is increasing (MAX_BUCKET's log base 2
77650997Sbostic 	 * * increases), we need to copy the current contents of the spare
77750997Sbostic 	 * split bucket to the next bucket.
77850997Sbostic 	 */
77952001Sbostic 	spare_ndx = __log2(hashp->MAX_BUCKET + 1);
78052001Sbostic 	if (spare_ndx > hashp->OVFL_POINT) {
78151061Sbostic 		hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
78251061Sbostic 		hashp->OVFL_POINT = spare_ndx;
78351061Sbostic 	}
78451061Sbostic 
78550997Sbostic 	if (new_bucket > hashp->HIGH_MASK) {
78650997Sbostic 		/* Starting a new doubling */
78750997Sbostic 		hashp->LOW_MASK = hashp->HIGH_MASK;
78850997Sbostic 		hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
78946366Sbostic 	}
79050997Sbostic 	/* Relocate records to the new bucket */
79157586Sbostic 	return (__split_page(hashp, old_bucket, new_bucket));
79250997Sbostic }
79346366Sbostic 
79446366Sbostic /*
79550997Sbostic  * If realloc guarantees that the pointer is not destroyed if the realloc
79650997Sbostic  * fails, then this routine can go away.
79750997Sbostic  */
79850997Sbostic static void *
79950997Sbostic hash_realloc(p_ptr, oldsize, newsize)
80050997Sbostic 	SEGMENT **p_ptr;
80150997Sbostic 	int oldsize, newsize;
80246366Sbostic {
80350997Sbostic 	register void *p;
80446366Sbostic 
80550997Sbostic 	if (p = malloc(newsize)) {
806*58016Sbostic 		memmove(p, *p_ptr, oldsize);
807*58016Sbostic 		memset(*p_ptr + oldsize, 0, newsize - oldsize);
80846366Sbostic 		free(*p_ptr);
80946366Sbostic 		*p_ptr = p;
81046366Sbostic 	}
81146366Sbostic 	return (p);
81246366Sbostic }
81346366Sbostic 
81447251Sbostic extern u_int
81557586Sbostic __call_hash(hashp, k, len)
81657586Sbostic 	HTAB *hashp;
81750997Sbostic 	char *k;
81850997Sbostic 	int len;
81946366Sbostic {
82050997Sbostic 	int n, bucket;
82150997Sbostic 
82246366Sbostic 	n = hashp->hash(k, len);
82346366Sbostic 	bucket = n & hashp->HIGH_MASK;
82450997Sbostic 	if (bucket > hashp->MAX_BUCKET)
82550997Sbostic 		bucket = bucket & hashp->LOW_MASK;
82650997Sbostic 	return (bucket);
82746366Sbostic }
82846366Sbostic 
82946366Sbostic /*
83050997Sbostic  * Allocate segment table.  On error, destroy the table and set errno.
83150997Sbostic  *
83250997Sbostic  * Returns 0 on success
83350997Sbostic  */
83446366Sbostic static int
83557586Sbostic alloc_segs(hashp, nsegs)
83657586Sbostic 	HTAB *hashp;
83750997Sbostic 	int nsegs;
83846366Sbostic {
83950997Sbostic 	register int i;
84050997Sbostic 	register SEGMENT store;
84146366Sbostic 
84250997Sbostic 	int save_errno;
84346366Sbostic 
84450997Sbostic 	if (!(hashp->dir = calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
84550997Sbostic 		save_errno = errno;
84657586Sbostic 		(void)hdestroy(hashp);
84750997Sbostic 		errno = save_errno;
84850997Sbostic 		return (-1);
84950997Sbostic 	}
85050997Sbostic 	/* Allocate segments */
85150997Sbostic 	store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT));
85250997Sbostic 	if (!store) {
85350997Sbostic 		save_errno = errno;
85457586Sbostic 		(void)hdestroy(hashp);
85550997Sbostic 		errno = save_errno;
85650997Sbostic 		return (-1);
85750997Sbostic 	}
85850997Sbostic 	for (i = 0; i < nsegs; i++, hashp->nsegs++)
85950997Sbostic 		hashp->dir[i] = &store[i << hashp->SSHIFT];
86050997Sbostic 	return (0);
86146366Sbostic }
86246366Sbostic 
86350997Sbostic #if BYTE_ORDER == LITTLE_ENDIAN
86446366Sbostic /*
86550997Sbostic  * Hashp->hdr needs to be byteswapped.
86650997Sbostic  */
86746366Sbostic static void
86850997Sbostic swap_header_copy(srcp, destp)
86950997Sbostic 	HASHHDR *srcp, *destp;
87046366Sbostic {
87150997Sbostic 	int i;
87246366Sbostic 
87350997Sbostic 	BLSWAP_COPY(srcp->magic, destp->magic);
87450997Sbostic 	BLSWAP_COPY(srcp->version, destp->version);
87550997Sbostic 	BLSWAP_COPY(srcp->lorder, destp->lorder);
87650997Sbostic 	BLSWAP_COPY(srcp->bsize, destp->bsize);
87750997Sbostic 	BLSWAP_COPY(srcp->bshift, destp->bshift);
87850997Sbostic 	BLSWAP_COPY(srcp->dsize, destp->dsize);
87950997Sbostic 	BLSWAP_COPY(srcp->ssize, destp->ssize);
88050997Sbostic 	BLSWAP_COPY(srcp->sshift, destp->sshift);
88151061Sbostic 	BLSWAP_COPY(srcp->ovfl_point, destp->ovfl_point);
88251061Sbostic 	BLSWAP_COPY(srcp->last_freed, destp->last_freed);
88350997Sbostic 	BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
88450997Sbostic 	BLSWAP_COPY(srcp->high_mask, destp->high_mask);
88550997Sbostic 	BLSWAP_COPY(srcp->low_mask, destp->low_mask);
88650997Sbostic 	BLSWAP_COPY(srcp->ffactor, destp->ffactor);
88750997Sbostic 	BLSWAP_COPY(srcp->nkeys, destp->nkeys);
88850997Sbostic 	BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
88950997Sbostic 	BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
89050997Sbostic 	for (i = 0; i < NCACHED; i++) {
89150997Sbostic 		BLSWAP_COPY(srcp->spares[i], destp->spares[i]);
89250997Sbostic 		BSSWAP_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
89350997Sbostic 	}
89446366Sbostic }
89546366Sbostic 
89646366Sbostic static void
89757586Sbostic swap_header(hashp)
89857586Sbostic 	HTAB *hashp;
89946366Sbostic {
90050997Sbostic 	HASHHDR *hdrp;
90150997Sbostic 	int i;
90246366Sbostic 
90350997Sbostic 	hdrp = &hashp->hdr;
90446366Sbostic 
90550997Sbostic 	BLSWAP(hdrp->magic);
90650997Sbostic 	BLSWAP(hdrp->version);
90750997Sbostic 	BLSWAP(hdrp->lorder);
90850997Sbostic 	BLSWAP(hdrp->bsize);
90950997Sbostic 	BLSWAP(hdrp->bshift);
91050997Sbostic 	BLSWAP(hdrp->dsize);
91150997Sbostic 	BLSWAP(hdrp->ssize);
91250997Sbostic 	BLSWAP(hdrp->sshift);
91351061Sbostic 	BLSWAP(hdrp->ovfl_point);
91451061Sbostic 	BLSWAP(hdrp->last_freed);
91550997Sbostic 	BLSWAP(hdrp->max_bucket);
91650997Sbostic 	BLSWAP(hdrp->high_mask);
91750997Sbostic 	BLSWAP(hdrp->low_mask);
91850997Sbostic 	BLSWAP(hdrp->ffactor);
91950997Sbostic 	BLSWAP(hdrp->nkeys);
92050997Sbostic 	BLSWAP(hdrp->hdrpages);
92150997Sbostic 	BLSWAP(hdrp->h_charkey);
92250997Sbostic 	for (i = 0; i < NCACHED; i++) {
92350997Sbostic 		BLSWAP(hdrp->spares[i]);
92450997Sbostic 		BSSWAP(hdrp->bitmaps[i]);
92550997Sbostic 	}
92646366Sbostic }
92750997Sbostic #endif
928