security/nss/lib/dbm/src/hash.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*-
     2  * Copyright (c) 1990, 1993, 1994
     3  *	The Regents of the University of California.  All rights reserved.
     4  *
     5  * This code is derived from software contributed to Berkeley by
     6  * Margo Seltzer.
     7  *
     8  * Redistribution and use in source and binary forms, with or without
     9  * modification, are permitted provided that the following conditions
    10  * are met:
    11  * 1. Redistributions of source code must retain the above copyright
    12  *    notice, this list of conditions and the following disclaimer.
    13  * 2. Redistributions in binary form must reproduce the above copyright
    14  *    notice, this list of conditions and the following disclaimer in the
    15  *    documentation and/or other materials provided with the distribution.
    16  * 3. ***REMOVED*** - see 
    17  *    ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
    18  * 4. Neither the name of the University nor the names of its contributors
    19  *    may be used to endorse or promote products derived from this software
    20  *    without specific prior written permission.
    21  *
    22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    32  * SUCH DAMAGE.
    33  */
    35 #if defined(LIBC_SCCS) && !defined(lint)
    36 static char sccsid[] = "@(#)hash.c	8.9 (Berkeley) 6/16/94";
    37 #endif /* LIBC_SCCS and not lint */
    39 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
    40 #include <sys/param.h>
    41 #endif
    43 #if !defined(macintosh)
    44 #ifdef XP_OS2
    45 #include <sys/types.h>
    46 #endif
    47 #include <sys/stat.h>
    48 #endif
    50 #if defined(macintosh)
    51 #include <unix.h>
    52 #include <unistd.h>
    53 #endif
    55 #include <errno.h>
    56 #include <fcntl.h>
    57 #include <stdio.h>
    58 #include <stdlib.h>
    59 #include <string.h>
    61 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh)
    62 #include <unistd.h>
    63 #endif
    64 #if defined(_WIN32) || defined(_WINDOWS) 
    65 #include <windows.h>
    66 #endif
    68 #include <assert.h>
    70 #include "mcom_db.h"
    71 #include "hash.h"
    72 #include "page.h"
    74 /*
    75 #include "extern.h"
    76 */
    77 static int   alloc_segs __P((HTAB *, int));
    78 static int   flush_meta __P((HTAB *));
    79 static int   hash_access __P((HTAB *, ACTION, DBT *, DBT *));
    80 static int   hash_close __P((DB *));
    81 static int   hash_delete __P((const DB *, const DBT *, uint));
    82 static int   hash_fd __P((const DB *));
    83 static int   hash_get __P((const DB *, const DBT *, DBT *, uint));
    84 static int   hash_put __P((const DB *, DBT *, const DBT *, uint));
    85 static void *hash_realloc __P((SEGMENT **, size_t, size_t));
    86 static int   hash_seq __P((const DB *, DBT *, DBT *, uint));
    87 static int   hash_sync __P((const DB *, uint));
    88 static int   hdestroy __P((HTAB *));
    89 static HTAB *init_hash __P((HTAB *, const char *, HASHINFO *));
    90 static int   init_htab __P((HTAB *, int));
    91 #if BYTE_ORDER == LITTLE_ENDIAN
    92 static void  swap_header __P((HTAB *));
    93 static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
    94 #endif
    96 /* Fast arithmetic, relying on powers of 2, */
    97 #define MOD(x, y)		((x) & ((y) - 1))
    99 #define RETURN_ERROR(ERR, LOC)	{ save_errno = ERR; goto LOC; }
   101 /* Return values */
   102 #define	SUCCESS	 (0)
   103 #define	DBM_ERROR	(-1)
   104 #define	ABNORMAL (1)
   106 #ifdef HASH_STATISTICS
   107 int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
   108 #endif
   110 /* A new Lou (montulli@mozilla.com) routine.
   111  *
   112  * The database is screwed.  
   113  *
   114  * This closes the file, flushing buffers as appropriate.
   115  */
   116 static void
   117 __remove_database(DB *dbp)
   118 {
   119 	HTAB *hashp = (HTAB *)dbp->internal;
   121 	assert(0);
   123 	if (!hashp)
   124 		return;
   125 	hdestroy(hashp);
   126 	dbp->internal = NULL; 
   127 }
   129 /************************** INTERFACE ROUTINES ***************************/
   130 /* OPEN/CLOSE */
   133 extern DB *
   134 __hash_open(const char *file, int flags, int mode, const HASHINFO *info, int dflags)
   135 {
   136 	HTAB *hashp=NULL;
   137 	struct stat statbuf;
   138 	DB *dbp;
   139 	int bpages, hdrsize, new_table, nsegs, save_errno;
   141 	if ((flags & O_ACCMODE) == O_WRONLY) {
   142 		errno = EINVAL;
   143 		return NULL;
   144 	}
   146 	/* zero the statbuffer so that
   147 	 * we can check it for a non-zero
   148 	 * date to see if stat succeeded
   149 	 */
   150 	memset(&statbuf, 0, sizeof(struct stat));
   152 	if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB)))) {
   153 		errno = ENOMEM;
   154 		return NULL;
   155 	}
   156 	hashp->fp = NO_FILE;
   157 	if(file)
   158 		hashp->filename = strdup(file);
   160 	/*
   161 	 * Even if user wants write only, we need to be able to read
   162 	 * the actual file, so we need to open it read/write. But, the
   163 	 * field in the hashp structure needs to be accurate so that
   164 	 * we can check accesses.
   165 	 */
   166 	hashp->flags = flags;
   168 	new_table = 0;
   169 	if (!file || (flags & O_TRUNC) 	|| (stat(file, &statbuf)  && (errno == ENOENT))) 
   170 	{
   171 		if (errno == ENOENT)
   172 			errno = 0; /* Just in case someone looks at errno */
   173 		new_table = 1;
   174 	}
   175 	else if(statbuf.st_mtime && statbuf.st_size == 0)
   176 	{
   177 		/* check for a zero length file and delete it
   178 	 	 * if it exists
   179 	 	 */
   180 		new_table = 1;
   181 	}
   182 	hashp->file_size = statbuf.st_size;
   184 	if (file) {				 
   185 #if defined(_WIN32) || defined(_WINDOWS) || defined (macintosh)  || defined(XP_OS2)
   186 		if ((hashp->fp = DBFILE_OPEN(file, flags | O_BINARY, mode)) == -1)
   187 			RETURN_ERROR(errno, error1);
   188 #else
   189 		if ((hashp->fp = open(file, flags, mode)) == -1)
   190 			RETURN_ERROR(errno, error1);
   191 		(void)fcntl(hashp->fp, F_SETFD, 1);
   192 #endif
   193 	}
   194 	if (new_table) {
   195 		if (!init_hash(hashp, file, (HASHINFO *)info))
   196 			RETURN_ERROR(errno, error1);
   197 	} else {
   198 		/* Table already exists */
   199 		if (info && info->hash)
   200 			hashp->hash = info->hash;
   201 		else
   202 			hashp->hash = __default_hash;
   204 		hdrsize = read(hashp->fp, (char *)&hashp->hdr, sizeof(HASHHDR));
   205 		if (hdrsize == -1)
   206 			RETURN_ERROR(errno, error1);
   207 		if (hdrsize != sizeof(HASHHDR))
   208 			RETURN_ERROR(EFTYPE, error1);
   209 #if BYTE_ORDER == LITTLE_ENDIAN
   210 		swap_header(hashp);
   211 #endif
   212 		/* Verify file type, versions and hash function */
   213 		if (hashp->MAGIC != HASHMAGIC)
   214 			RETURN_ERROR(EFTYPE, error1);
   215 #define	OLDHASHVERSION	1
   216 		if (hashp->VERSION != HASHVERSION &&
   217 		    hashp->VERSION != OLDHASHVERSION)
   218 			RETURN_ERROR(EFTYPE, error1);
   219 		if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
   220 			RETURN_ERROR(EFTYPE, error1);
   221 		if (hashp->NKEYS < 0) /* Old bad database. */
   222 			RETURN_ERROR(EFTYPE, error1);
   224 		/*
   225 		 * Figure out how many segments we need.  Max_Bucket is the
   226 		 * maximum bucket number, so the number of buckets is
   227 		 * max_bucket + 1.
   228 		 */
   229 		nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
   230 			 hashp->SGSIZE;
   231 		hashp->nsegs = 0;
   232 		if (alloc_segs(hashp, nsegs))
   233 			/* If alloc_segs fails, errno will have been set.  */
   234 			RETURN_ERROR(errno, error1);
   235 		/* Read in bitmaps */
   236 		bpages = (hashp->SPARES[hashp->OVFL_POINT] +
   237 		    (hashp->BSIZE << BYTE_SHIFT) - 1) >>
   238 		    (hashp->BSHIFT + BYTE_SHIFT);
   240 		hashp->nmaps = bpages;
   241 		(void)memset(&hashp->mapp[0], 0, bpages * sizeof(uint32 *));
   242 	}
   244 	/* Initialize Buffer Manager */
   245 	if (info && info->cachesize)
   246 		__buf_init(hashp, (int32) info->cachesize);
   247 	else
   248 		__buf_init(hashp, DEF_BUFSIZE);
   250 	hashp->new_file = new_table;
   251 #ifdef macintosh
   252 	hashp->save_file = file && !(hashp->flags & O_RDONLY);
   253 #else
   254 	hashp->save_file = file && (hashp->flags & O_RDWR);
   255 #endif
   256 	hashp->cbucket = -1;
   257 	if (!(dbp = (DB *)malloc(sizeof(DB)))) {
   258 		RETURN_ERROR(ENOMEM, error1);
   259 	}
   260 	dbp->internal = hashp;
   261 	dbp->close = hash_close;
   262 	dbp->del = hash_delete;
   263 	dbp->fd = hash_fd;
   264 	dbp->get = hash_get;
   265 	dbp->put = hash_put;
   266 	dbp->seq = hash_seq;
   267 	dbp->sync = hash_sync;
   268 	dbp->type = DB_HASH;
   270 #ifdef HASH_STATISTICS
   271 	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
   272 #endif
   273 	return (dbp);
   275 error1:
   276 	hdestroy(hashp);
   277 	errno = save_errno;
   278 	return (NULL);
   279 }
   281 static int
   282 hash_close(DB *dbp)
   283 {
   284 	HTAB *hashp;
   285 	int retval;
   287 	if (!dbp)
   288 		return (DBM_ERROR);
   290 	hashp = (HTAB *)dbp->internal;
   291 	if(!hashp)
   292 		return (DBM_ERROR);
   294 	retval = hdestroy(hashp);
   295 	free(dbp);
   296 	return (retval);
   297 }
   299 static int hash_fd(const DB *dbp)
   300 {
   301 	HTAB *hashp;
   303 	if (!dbp)
   304 		return (DBM_ERROR);
   306 	hashp = (HTAB *)dbp->internal;
   307 	if(!hashp)
   308 		return (DBM_ERROR);
   310 	if (hashp->fp == -1) {
   311 		errno = ENOENT;
   312 		return (-1);
   313 	}
   314 	return (hashp->fp);
   315 }
   317 /************************** LOCAL CREATION ROUTINES **********************/
   318 static HTAB *
   319 init_hash(HTAB *hashp, const char *file, HASHINFO *info)
   320 {
   321 	struct stat statbuf;
   322 	int nelem;
   324 	nelem = 1;
   325 	hashp->NKEYS = 0;
   326 	hashp->LORDER = BYTE_ORDER;
   327 	hashp->BSIZE = DEF_BUCKET_SIZE;
   328 	hashp->BSHIFT = DEF_BUCKET_SHIFT;
   329 	hashp->SGSIZE = DEF_SEGSIZE;
   330 	hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
   331 	hashp->DSIZE = DEF_DIRSIZE;
   332 	hashp->FFACTOR = DEF_FFACTOR;
   333 	hashp->hash = __default_hash;
   334 	memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
   335 	memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
   337 	/* Fix bucket size to be optimal for file system */
   338 	if (file != NULL) {
   339 		if (stat(file, &statbuf))
   340 			return (NULL);
   342 #if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) && !defined(XP_OS2)
   343 #if defined(__QNX__) && !defined(__QNXNTO__)
   344 		hashp->BSIZE = 512; /* preferred blk size on qnx4 */
   345 #else
   346 		hashp->BSIZE = statbuf.st_blksize;
   347 #endif
   349 		/* new code added by Lou to reduce block
   350 		 * size down below MAX_BSIZE
   351 		 */
   352 		if (hashp->BSIZE > MAX_BSIZE)
   353 			hashp->BSIZE = MAX_BSIZE;
   354 #endif
   355 		hashp->BSHIFT = __log2((uint32)hashp->BSIZE);
   356 	}
   358 	if (info) {
   359 		if (info->bsize) {
   360 			/* Round pagesize up to power of 2 */
   361 			hashp->BSHIFT = __log2(info->bsize);
   362 			hashp->BSIZE = 1 << hashp->BSHIFT;
   363 			if (hashp->BSIZE > MAX_BSIZE) {
   364 				errno = EINVAL;
   365 				return (NULL);
   366 			}
   367 		}
   368 		if (info->ffactor)
   369 			hashp->FFACTOR = info->ffactor;
   370 		if (info->hash)
   371 			hashp->hash = info->hash;
   372 		if (info->nelem)
   373 			nelem = info->nelem;
   374 		if (info->lorder) {
   375 			if (info->lorder != BIG_ENDIAN &&
   376 			    info->lorder != LITTLE_ENDIAN) {
   377 				errno = EINVAL;
   378 				return (NULL);
   379 			}
   380 			hashp->LORDER = info->lorder;
   381 		}
   382 	}
   383 	/* init_htab sets errno if it fails */
   384 	if (init_htab(hashp, nelem))
   385 		return (NULL);
   386 	else
   387 		return (hashp);
   388 }
   389 /*
   390  * This calls alloc_segs which may run out of memory.  Alloc_segs will 
   391  * set errno, so we just pass the error information along.
   392  *
   393  * Returns 0 on No Error
   394  */
   395 static int
   396 init_htab(HTAB *hashp, int nelem)
   397 {
   398 	register int nbuckets, nsegs;
   399 	int l2;
   401 	/*
   402 	 * Divide number of elements by the fill factor and determine a
   403 	 * desired number of buckets.  Allocate space for the next greater
   404 	 * power of two number of buckets.
   405 	 */
   406 	nelem = (nelem - 1) / hashp->FFACTOR + 1;
   408 	l2 = __log2((uint32)PR_MAX(nelem, 2));
   409 	nbuckets = 1 << l2;
   411 	hashp->SPARES[l2] = l2 + 1;
   412 	hashp->SPARES[l2 + 1] = l2 + 1;
   413 	hashp->OVFL_POINT = l2;
   414 	hashp->LAST_FREED = 2;
   416 	/* First bitmap page is at: splitpoint l2 page offset 1 */
   417 	if (__ibitmap(hashp, (int)OADDR_OF(l2, 1), l2 + 1, 0))
   418 		return (-1);
   420 	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
   421 	hashp->HIGH_MASK = (nbuckets << 1) - 1;
   422 	hashp->HDRPAGES = ((PR_MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
   423 	    hashp->BSHIFT) + 1;
   425 	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
   426 	nsegs = 1 << __log2((uint32)nsegs);
   428 	if (nsegs > hashp->DSIZE)
   429 		hashp->DSIZE = nsegs;
   430 	return (alloc_segs(hashp, nsegs));
   431 }
   433 /********************** DESTROY/CLOSE ROUTINES ************************/
   435 /*
   436  * Flushes any changes to the file if necessary and destroys the hashp
   437  * structure, freeing all allocated space.
   438  */
   439 static int
   440 hdestroy(HTAB *hashp)
   441 {
   442 	int i, save_errno;
   444 	save_errno = 0;
   446 #ifdef HASH_STATISTICS
   447 	(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
   448 	    hash_accesses, hash_collisions);
   449 	(void)fprintf(stderr, "hdestroy: expansions %ld\n",
   450 	    hash_expansions);
   451 	(void)fprintf(stderr, "hdestroy: overflows %ld\n",
   452 	    hash_overflows);
   453 	(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
   454 	    hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
   456 	for (i = 0; i < NCACHED; i++)
   457 		(void)fprintf(stderr,
   458 		    "spares[%d] = %d\n", i, hashp->SPARES[i]);
   459 #endif
   460 	/*
   461 	 * Call on buffer manager to free buffers, and if required,
   462 	 * write them to disk.
   463 	 */
   464 	if (__buf_free(hashp, 1, hashp->save_file))
   465 		save_errno = errno;
   466 	if (hashp->dir) {
   467 		free(*hashp->dir);	/* Free initial segments */
   468 		/* Free extra segments */
   469 		while (hashp->exsegs--)
   470 			free(hashp->dir[--hashp->nsegs]);
   471 		free(hashp->dir);
   472 	}
   473 	if (flush_meta(hashp) && !save_errno)
   474 		save_errno = errno;
   475 	/* Free Bigmaps */
   476 	for (i = 0; i < hashp->nmaps; i++)
   477 		if (hashp->mapp[i])
   478 			free(hashp->mapp[i]);
   480 	if (hashp->fp != -1)
   481 		(void)close(hashp->fp);
   483 	if(hashp->filename) {
   484 #if defined(_WIN32) || defined(_WINDOWS) || defined(XP_OS2)
   485 		if (hashp->is_temp)
   486 			(void)unlink(hashp->filename);
   487 #endif
   488 		free(hashp->filename);
   489 	}
   490 	if (hashp->tmp_buf)
   491 	    free(hashp->tmp_buf);
   492 	if (hashp->tmp_key)
   493 	    free(hashp->tmp_key);
   494 	free(hashp);
   495 	if (save_errno) {
   496 		errno = save_errno;
   497 		return (DBM_ERROR);
   498 	}
   499 	return (SUCCESS);
   500 }
   502 #if defined(_WIN32) || defined(_WINDOWS) 
   503 /*
   504  * Close and reopen file to force file length update on windows. 
   505  *
   506  * Returns:
   507  *	 0 == OK
   508  *	-1 DBM_ERROR
   509  */
   510 static int
   511 update_EOF(HTAB *hashp)
   512 {
   513 #if defined(DBM_REOPEN_ON_FLUSH)
   514 	char *      file       = hashp->filename;
   515 	off_t       file_size;
   516 	int         flags;
   517 	int         mode       = -1;
   518 	struct stat statbuf;
   520 	memset(&statbuf, 0, sizeof statbuf);
   522 	/* make sure we won't lose the file by closing it. */
   523 	if (!file || (stat(file, &statbuf)  && (errno == ENOENT)))  {
   524 		/* pretend we did it. */
   525 		return 0;
   526 	}
   528 	(void)close(hashp->fp);
   530 	flags = hashp->flags & ~(O_TRUNC | O_CREAT | O_EXCL);
   532 	if ((hashp->fp = DBFILE_OPEN(file, flags | O_BINARY, mode)) == -1)
   533 		return -1;
   534 	file_size = lseek(hashp->fp, (off_t)0, SEEK_END);
   535 	if (file_size == -1) 
   536 		return -1;
   537 	hashp->file_size = file_size;
   538 	return 0;
   539 #else
   540 	int    fd        = hashp->fp;
   541 	off_t  file_size = lseek(fd, (off_t)0, SEEK_END);
   542 	HANDLE handle    = (HANDLE)_get_osfhandle(fd);
   543 	BOOL   cool      = FlushFileBuffers(handle);
   544 #ifdef DEBUG3
   545 	if (!cool) {
   546 		DWORD err = GetLastError();
   547 		(void)fprintf(stderr,
   548 			"FlushFileBuffers failed, last error = %d, 0x%08x\n",
   549 			err, err);
   550 	}
   551 #endif
   552 	if (file_size == -1) 
   553 		return -1;
   554 	hashp->file_size = file_size;
   555 	return cool ? 0 : -1;
   556 #endif
   557 }
   558 #endif
   560 /*
   561  * Write modified pages to disk
   562  *
   563  * Returns:
   564  *	 0 == OK
   565  *	-1 DBM_ERROR
   566  */
   567 static int
   568 hash_sync(const DB *dbp, uint flags)
   569 {
   570 	HTAB *hashp;
   572 	if (flags != 0) {
   573 		errno = EINVAL;
   574 		return (DBM_ERROR);
   575 	}
   577 	if (!dbp)
   578 		return (DBM_ERROR);
   580 	hashp = (HTAB *)dbp->internal;
   581 	if(!hashp)
   582 		return (DBM_ERROR);
   584 	if (!hashp->save_file)
   585 		return (0);
   586 	if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
   587 		return (DBM_ERROR);
   588 #if defined(_WIN32) || defined(_WINDOWS) 
   589 	if (hashp->updateEOF && hashp->filename && !hashp->is_temp) {
   590 		int status = update_EOF(hashp);
   591 		hashp->updateEOF = 0;
   592 		if (status)
   593 			return status;
   594 	}
   595 #endif
   596 	hashp->new_file = 0;
   597 	return (0);
   598 }
   600 /*
   601  * Returns:
   602  *	 0 == OK
   603  *	-1 indicates that errno should be set
   604  */
   605 static int
   606 flush_meta(HTAB *hashp)
   607 {
   608 	HASHHDR *whdrp;
   609 #if BYTE_ORDER == LITTLE_ENDIAN
   610 	HASHHDR whdr;
   611 #endif
   612 	int fp, i, wsize;
   614 	if (!hashp->save_file)
   615 		return (0);
   616 	hashp->MAGIC = HASHMAGIC;
   617 	hashp->VERSION = HASHVERSION;
   618 	hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
   620 	fp = hashp->fp;
   621 	whdrp = &hashp->hdr;
   622 #if BYTE_ORDER == LITTLE_ENDIAN
   623 	whdrp = &whdr;
   624 	swap_header_copy(&hashp->hdr, whdrp);
   625 #endif
   626 	if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
   627 	    ((wsize = write(fp, (char*)whdrp, sizeof(HASHHDR))) == -1))
   628 		return (-1);
   629 	else
   630 		if (wsize != sizeof(HASHHDR)) {
   631 			errno = EFTYPE;
   632 			hashp->dbmerrno = errno;
   633 			return (-1);
   634 		}
   635 	for (i = 0; i < NCACHED; i++)
   636 		if (hashp->mapp[i])
   637 			if (__put_page(hashp, (char *)hashp->mapp[i],
   638 				hashp->BITMAPS[i], 0, 1))
   639 				return (-1);
   640 	return (0);
   641 }
   643 /*******************************SEARCH ROUTINES *****************************/
   644 /*
   645  * All the access routines return
   646  *
   647  * Returns:
   648  *	 0 on SUCCESS
   649  *	 1 to indicate an external DBM_ERROR (i.e. key not found, etc)
   650  *	-1 to indicate an internal DBM_ERROR (i.e. out of memory, etc)
   651  */
   652 static int
   653 hash_get(
   654 	const DB *dbp,
   655 	const DBT *key,
   656 	DBT *data,
   657 	uint flag)
   658 {
   659 	HTAB *hashp;
   660 	int rv;
   662 	hashp = (HTAB *)dbp->internal;
   663 	if (!hashp)
   664 		return (DBM_ERROR);
   666 	if (flag) {
   667 		hashp->dbmerrno = errno = EINVAL;
   668 		return (DBM_ERROR);
   669 	}
   671 	rv = hash_access(hashp, HASH_GET, (DBT *)key, data);
   673 	if(rv == DATABASE_CORRUPTED_ERROR)
   674 	  {
   675 #if defined(unix) && defined(DEBUG)
   676 		printf("\n\nDBM Database has been corrupted, tell Lou...\n\n");
   677 #endif
   678 	  	__remove_database((DB *)dbp);
   679 	  }
   681 	return(rv);
   682 }
   684 static int
   685 hash_put(
   686 	const DB *dbp,
   687 	DBT *key,
   688 	const DBT *data,
   689 	uint flag)
   690 {
   691 	HTAB *hashp;
   692 	int rv;
   694 	hashp = (HTAB *)dbp->internal;
   695 	if (!hashp)
   696 		return (DBM_ERROR);
   698 	if (flag && flag != R_NOOVERWRITE) {
   699 		hashp->dbmerrno = errno = EINVAL;
   700 		return (DBM_ERROR);
   701 	}
   702 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
   703 		hashp->dbmerrno = errno = EPERM;
   704 		return (DBM_ERROR);
   705 	}
   707 	rv =  hash_access(hashp, flag == R_NOOVERWRITE ?
   708 	    HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data);
   710 	if(rv == DATABASE_CORRUPTED_ERROR)
   711 	  {
   712 #if defined(unix) && defined(DEBUG)
   713 		printf("\n\nDBM Database has been corrupted, tell Lou...\n\n");
   714 #endif
   715 	  	__remove_database((DB *)dbp);
   716 	  }
   718 	return(rv);
   719 }
   721 static int
   722 hash_delete(
   723 	const DB *dbp,
   724 	const DBT *key,
   725 	uint flag)		/* Ignored */
   726 {
   727 	HTAB *hashp;
   728 	int rv;
   730 	hashp = (HTAB *)dbp->internal;
   731 	if (!hashp)
   732 		return (DBM_ERROR);
   734 	if (flag && flag != R_CURSOR) {
   735 		hashp->dbmerrno = errno = EINVAL;
   736 		return (DBM_ERROR);
   737 	}
   738 	if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
   739 		hashp->dbmerrno = errno = EPERM;
   740 		return (DBM_ERROR);
   741 	}
   742 	rv = hash_access(hashp, HASH_DELETE, (DBT *)key, NULL);
   744 	if(rv == DATABASE_CORRUPTED_ERROR)
   745 	  {
   746 #if defined(unix) && defined(DEBUG)
   747 		printf("\n\nDBM Database has been corrupted, tell Lou...\n\n");
   748 #endif
   749 	  	__remove_database((DB *)dbp);
   750 	  }
   752 	return(rv);
   753 }
   755 #define MAX_OVERFLOW_HASH_ACCESS_LOOPS 2000
   756 /*
   757  * Assume that hashp has been set in wrapper routine.
   758  */
   759 static int
   760 hash_access(
   761 	HTAB *hashp,
   762 	ACTION action,
   763 	DBT *key, DBT *val)
   764 {
   765 	register BUFHEAD *rbufp;
   766 	BUFHEAD *bufp, *save_bufp;
   767 	register uint16 *bp;
   768 	register long n, ndx, off;
   769 	register size_t size;
   770 	register char *kp;
   771 	uint16 pageno;
   772 	uint32 ovfl_loop_count=0;
   773     int32 last_overflow_page_no = -1;
   775 #ifdef HASH_STATISTICS
   776 	hash_accesses++;
   777 #endif
   779 	off = hashp->BSIZE;
   780 	size = key->size;
   781 	kp = (char *)key->data;
   782 	rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
   783 	if (!rbufp)
   784 		return (DATABASE_CORRUPTED_ERROR);
   785 	save_bufp = rbufp;
   787 	/* Pin the bucket chain */
   788 	rbufp->flags |= BUF_PIN;
   789 	for (bp = (uint16 *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
   790 	{
   792 		if (bp[1] >= REAL_KEY) {
   793 			/* Real key/data pair */
   794 			if (size == (unsigned long)(off - *bp) &&
   795 			    memcmp(kp, rbufp->page + *bp, size) == 0)
   796 				goto found;
   797 			off = bp[1];
   798 #ifdef HASH_STATISTICS
   799 			hash_collisions++;
   800 #endif
   801 			bp += 2;
   802 			ndx += 2;
   803 		} else if (bp[1] == OVFLPAGE) {
   805             /* database corruption: overflow loop detection */
   806             if(last_overflow_page_no == (int32)*bp)
   807     			return (DATABASE_CORRUPTED_ERROR);
   809             last_overflow_page_no = *bp;
   811 			rbufp = __get_buf(hashp, *bp, rbufp, 0);
   812 			if (!rbufp) {
   813 				save_bufp->flags &= ~BUF_PIN;
   814 				return (DBM_ERROR);
   815 			}
   817             ovfl_loop_count++;
   818             if(ovfl_loop_count > MAX_OVERFLOW_HASH_ACCESS_LOOPS)
   819     			return (DATABASE_CORRUPTED_ERROR);
   821 			/* FOR LOOP INIT */
   822 			bp = (uint16 *)rbufp->page;
   823 			n = *bp++;
   824 			ndx = 1;
   825 			off = hashp->BSIZE;
   826 		} else if (bp[1] < REAL_KEY) {
   827 			if ((ndx =
   828 			    __find_bigpair(hashp, rbufp, ndx, kp, (int)size)) > 0)
   829 				goto found;
   830 			if (ndx == -2) {
   831 				bufp = rbufp;
   832 				if (!(pageno =
   833 				    __find_last_page(hashp, &bufp))) {
   834 					ndx = 0;
   835 					rbufp = bufp;
   836 					break;	/* FOR */
   837 				}
   838 				rbufp = __get_buf(hashp, pageno, bufp, 0);
   839 				if (!rbufp) {
   840 					save_bufp->flags &= ~BUF_PIN;
   841 					return (DBM_ERROR);
   842 				}
   843 				/* FOR LOOP INIT */
   844 				bp = (uint16 *)rbufp->page;
   845 				n = *bp++;
   846 				ndx = 1;
   847 				off = hashp->BSIZE;
   848 			} else {
   849 				save_bufp->flags &= ~BUF_PIN;
   850 				return (DBM_ERROR);
   852 			}
   853 		}
   854 	}
   856 	/* Not found */
   857 	switch (action) {
   858 	case HASH_PUT:
   859 	case HASH_PUTNEW:
   860 		if (__addel(hashp, rbufp, key, val)) {
   861 			save_bufp->flags &= ~BUF_PIN;
   862 			return (DBM_ERROR);
   863 		} else {
   864 			save_bufp->flags &= ~BUF_PIN;
   865 			return (SUCCESS);
   866 		}
   867 	case HASH_GET:
   868 	case HASH_DELETE:
   869 	default:
   870 		save_bufp->flags &= ~BUF_PIN;
   871 		return (ABNORMAL);
   872 	}
   874 found:
   875 	switch (action) {
   876 	case HASH_PUTNEW:
   877 		save_bufp->flags &= ~BUF_PIN;
   878 		return (ABNORMAL);
   879 	case HASH_GET:
   880 		bp = (uint16 *)rbufp->page;
   881 		if (bp[ndx + 1] < REAL_KEY) {
   882 			if (__big_return(hashp, rbufp, ndx, val, 0))
   883 				return (DBM_ERROR);
   884 		} else {
   885 			val->data = (uint8 *)rbufp->page + (int)bp[ndx + 1];
   886 			val->size = bp[ndx] - bp[ndx + 1];
   887 		}
   888 		break;
   889 	case HASH_PUT:
   890 		if ((__delpair(hashp, rbufp, ndx)) ||
   891 		    (__addel(hashp, rbufp, key, val))) {
   892 			save_bufp->flags &= ~BUF_PIN;
   893 			return (DBM_ERROR);
   894 		}
   895 		break;
   896 	case HASH_DELETE:
   897 		if (__delpair(hashp, rbufp, ndx))
   898 			return (DBM_ERROR);
   899 		break;
   900 	default:
   901 		abort();
   902 	}
   903 	save_bufp->flags &= ~BUF_PIN;
   904 	return (SUCCESS);
   905 }
   907 static int
   908 hash_seq(
   909 	const DB *dbp,
   910 	DBT *key, DBT *data,
   911 	uint flag)
   912 {
   913 	register uint32 bucket;
   914 	register BUFHEAD *bufp;
   915 	HTAB *hashp;
   916 	uint16 *bp, ndx;
   918 	hashp = (HTAB *)dbp->internal;
   919 	if (!hashp)
   920 		return (DBM_ERROR);
   922 	if (flag && flag != R_FIRST && flag != R_NEXT) {
   923 		hashp->dbmerrno = errno = EINVAL;
   924 		return (DBM_ERROR);
   925 	}
   926 #ifdef HASH_STATISTICS
   927 	hash_accesses++;
   928 #endif
   929 	if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
   930 		hashp->cbucket = 0;
   931 		hashp->cndx = 1;
   932 		hashp->cpage = NULL;
   933 	}
   935 	for (bp = NULL; !bp || !bp[0]; ) {
   936 		if (!(bufp = hashp->cpage)) {
   937 			for (bucket = hashp->cbucket;
   938 			    bucket <= (uint32)hashp->MAX_BUCKET;
   939 			    bucket++, hashp->cndx = 1) {
   940 				bufp = __get_buf(hashp, bucket, NULL, 0);
   941 				if (!bufp)
   942 					return (DBM_ERROR);
   943 				hashp->cpage = bufp;
   944 				bp = (uint16 *)bufp->page;
   945 				if (bp[0])
   946 					break;
   947 			}
   948 			hashp->cbucket = bucket;
   949 			if (hashp->cbucket > hashp->MAX_BUCKET) {
   950 				hashp->cbucket = -1;
   951 				return (ABNORMAL);
   952 			}
   953 		} else
   954 			bp = (uint16 *)hashp->cpage->page;
   956 #ifdef DEBUG
   957 		assert(bp);
   958 		assert(bufp);
   959 #endif
   960 		while (bp[hashp->cndx + 1] == OVFLPAGE) {
   961 			bufp = hashp->cpage =
   962 			    __get_buf(hashp, bp[hashp->cndx], bufp, 0);
   963 			if (!bufp)
   964 				return (DBM_ERROR);
   965 			bp = (uint16 *)(bufp->page);
   966 			hashp->cndx = 1;
   967 		}
   968 		if (!bp[0]) {
   969 			hashp->cpage = NULL;
   970 			++hashp->cbucket;
   971 		}
   972 	}
   973 	ndx = hashp->cndx;
   974 	if (bp[ndx + 1] < REAL_KEY) {
   975 		if (__big_keydata(hashp, bufp, key, data, 1))
   976 			return (DBM_ERROR);
   977 	} else {
   978 		key->data = (uint8 *)hashp->cpage->page + bp[ndx];
   979 		key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
   980 		data->data = (uint8 *)hashp->cpage->page + bp[ndx + 1];
   981 		data->size = bp[ndx] - bp[ndx + 1];
   982 		ndx += 2;
   983 		if (ndx > bp[0]) {
   984 			hashp->cpage = NULL;
   985 			hashp->cbucket++;
   986 			hashp->cndx = 1;
   987 		} else
   988 			hashp->cndx = ndx;
   989 	}
   990 	return (SUCCESS);
   991 }
   993 /********************************* UTILITIES ************************/
   995 /*
   996  * Returns:
   997  *	 0 ==> OK
   998  *	-1 ==> Error
   999  */
  1000 extern int
  1001 __expand_table(HTAB *hashp)
  1003 	uint32 old_bucket, new_bucket;
  1004 	int new_segnum, spare_ndx;
  1005 	size_t dirsize;
  1007 #ifdef HASH_STATISTICS
  1008 	hash_expansions++;
  1009 #endif
  1010 	new_bucket = ++hashp->MAX_BUCKET;
  1011 	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
  1013 	new_segnum = new_bucket >> hashp->SSHIFT;
  1015 	/* Check if we need a new segment */
  1016 	if (new_segnum >= hashp->nsegs) {
  1017 		/* Check if we need to expand directory */
  1018 		if (new_segnum >= hashp->DSIZE) {
  1019 			/* Reallocate directory */
  1020 			dirsize = hashp->DSIZE * sizeof(SEGMENT *);
  1021 			if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
  1022 				return (-1);
  1023 			hashp->DSIZE = dirsize << 1;
  1025 		if ((hashp->dir[new_segnum] =
  1026 		    (SEGMENT)calloc((size_t)hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
  1027 			return (-1);
  1028 		hashp->exsegs++;
  1029 		hashp->nsegs++;
  1031 	/*
  1032 	 * If the split point is increasing (MAX_BUCKET's log base 2
  1033 	 * * increases), we need to copy the current contents of the spare
  1034 	 * split bucket to the next bucket.
  1035 	 */
  1036 	spare_ndx = __log2((uint32)(hashp->MAX_BUCKET + 1));
  1037 	if (spare_ndx > hashp->OVFL_POINT) {
  1038 		hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
  1039 		hashp->OVFL_POINT = spare_ndx;
  1042 	if (new_bucket > (uint32)hashp->HIGH_MASK) {
  1043 		/* Starting a new doubling */
  1044 		hashp->LOW_MASK = hashp->HIGH_MASK;
  1045 		hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
  1047 	/* Relocate records to the new bucket */
  1048 	return (__split_page(hashp, old_bucket, new_bucket));
  1051 /*
  1052  * If realloc guarantees that the pointer is not destroyed if the realloc
  1053  * fails, then this routine can go away.
  1054  */
  1055 static void *
  1056 hash_realloc(
  1057 	SEGMENT **p_ptr,
  1058 	size_t oldsize, size_t newsize)
  1060 	register void *p;
  1062 	if ((p = malloc(newsize))) {
  1063 		memmove(p, *p_ptr, oldsize);
  1064 		memset((char *)p + oldsize, 0, newsize - oldsize);
  1065 		free(*p_ptr);
  1066 		*p_ptr = (SEGMENT *)p;
  1068 	return (p);
  1071 extern uint32
  1072 __call_hash(HTAB *hashp, char *k, size_t len)
  1074 	uint32 n, bucket;
  1076 	n = hashp->hash(k, len);
  1077 	bucket = n & hashp->HIGH_MASK;
  1078 	if (bucket > (uint32)hashp->MAX_BUCKET)
  1079 		bucket = bucket & hashp->LOW_MASK;
  1080 	return (bucket);
  1083 /*
  1084  * Allocate segment table.  On error, set errno.
  1086  * Returns 0 on success
  1087  */
  1088 static int
  1089 alloc_segs(
  1090 	HTAB *hashp,
  1091 	int nsegs)
  1093 	register int i;
  1094 	register SEGMENT store;
  1096 	if ((hashp->dir =
  1097 	    (SEGMENT *)calloc((size_t)hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
  1098 		errno = ENOMEM;
  1099 		return (-1);
  1101 	/* Allocate segments */
  1102 	if ((store =
  1103 	    (SEGMENT)calloc((size_t)nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
  1104 		errno = ENOMEM;
  1105 		return (-1);
  1107 	for (i = 0; i < nsegs; i++, hashp->nsegs++)
  1108 		hashp->dir[i] = &store[i << hashp->SSHIFT];
  1109 	return (0);
  1112 #if BYTE_ORDER == LITTLE_ENDIAN
  1113 /*
  1114  * Hashp->hdr needs to be byteswapped.
  1115  */
  1116 static void
  1117 swap_header_copy(
  1118 	HASHHDR *srcp, HASHHDR *destp)
  1120 	int i;
  1122 	P_32_COPY(srcp->magic, destp->magic);
  1123 	P_32_COPY(srcp->version, destp->version);
  1124 	P_32_COPY(srcp->lorder, destp->lorder);
  1125 	P_32_COPY(srcp->bsize, destp->bsize);
  1126 	P_32_COPY(srcp->bshift, destp->bshift);
  1127 	P_32_COPY(srcp->dsize, destp->dsize);
  1128 	P_32_COPY(srcp->ssize, destp->ssize);
  1129 	P_32_COPY(srcp->sshift, destp->sshift);
  1130 	P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
  1131 	P_32_COPY(srcp->last_freed, destp->last_freed);
  1132 	P_32_COPY(srcp->max_bucket, destp->max_bucket);
  1133 	P_32_COPY(srcp->high_mask, destp->high_mask);
  1134 	P_32_COPY(srcp->low_mask, destp->low_mask);
  1135 	P_32_COPY(srcp->ffactor, destp->ffactor);
  1136 	P_32_COPY(srcp->nkeys, destp->nkeys);
  1137 	P_32_COPY(srcp->hdrpages, destp->hdrpages);
  1138 	P_32_COPY(srcp->h_charkey, destp->h_charkey);
  1139 	for (i = 0; i < NCACHED; i++) {
  1140 		P_32_COPY(srcp->spares[i], destp->spares[i]);
  1141 		P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
  1145 static void
  1146 swap_header(HTAB *hashp)
  1148 	HASHHDR *hdrp;
  1149 	int i;
  1151 	hdrp = &hashp->hdr;
  1153 	M_32_SWAP(hdrp->magic);
  1154 	M_32_SWAP(hdrp->version);
  1155 	M_32_SWAP(hdrp->lorder);
  1156 	M_32_SWAP(hdrp->bsize);
  1157 	M_32_SWAP(hdrp->bshift);
  1158 	M_32_SWAP(hdrp->dsize);
  1159 	M_32_SWAP(hdrp->ssize);
  1160 	M_32_SWAP(hdrp->sshift);
  1161 	M_32_SWAP(hdrp->ovfl_point);
  1162 	M_32_SWAP(hdrp->last_freed);
  1163 	M_32_SWAP(hdrp->max_bucket);
  1164 	M_32_SWAP(hdrp->high_mask);
  1165 	M_32_SWAP(hdrp->low_mask);
  1166 	M_32_SWAP(hdrp->ffactor);
  1167 	M_32_SWAP(hdrp->nkeys);
  1168 	M_32_SWAP(hdrp->hdrpages);
  1169 	M_32_SWAP(hdrp->h_charkey);
  1170 	for (i = 0; i < NCACHED; i++) {
  1171 		M_32_SWAP(hdrp->spares[i]);
  1172 		M_16_SWAP(hdrp->bitmaps[i]);
  1175 #endif

mercurial