1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/dbm/src/h_bigkey.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,709 @@ 1.4 +/*- 1.5 + * Copyright (c) 1990, 1993, 1994 1.6 + * The Regents of the University of California. All rights reserved. 1.7 + * 1.8 + * This code is derived from software contributed to Berkeley by 1.9 + * Margo Seltzer. 1.10 + * 1.11 + * Redistribution and use in source and binary forms, with or without 1.12 + * modification, are permitted provided that the following conditions 1.13 + * are met: 1.14 + * 1. Redistributions of source code must retain the above copyright 1.15 + * notice, this list of conditions and the following disclaimer. 1.16 + * 2. Redistributions in binary form must reproduce the above copyright 1.17 + * notice, this list of conditions and the following disclaimer in the 1.18 + * documentation and/or other materials provided with the distribution. 1.19 + * 3. ***REMOVED*** - see 1.20 + * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change 1.21 + * 4. Neither the name of the University nor the names of its contributors 1.22 + * may be used to endorse or promote products derived from this software 1.23 + * without specific prior written permission. 1.24 + * 1.25 + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1.26 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.27 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.28 + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 1.29 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1.30 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1.31 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1.32 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1.33 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1.34 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1.35 + * SUCH DAMAGE. 1.36 + */ 1.37 + 1.38 +#if defined(LIBC_SCCS) && !defined(lint) 1.39 +static char sccsid[] = "@(#)hash_bigkey.c 8.3 (Berkeley) 5/31/94"; 1.40 +#endif /* LIBC_SCCS and not lint */ 1.41 + 1.42 +/* 1.43 + * PACKAGE: hash 1.44 + * DESCRIPTION: 1.45 + * Big key/data handling for the hashing package. 1.46 + * 1.47 + * ROUTINES: 1.48 + * External 1.49 + * __big_keydata 1.50 + * __big_split 1.51 + * __big_insert 1.52 + * __big_return 1.53 + * __big_delete 1.54 + * __find_last_page 1.55 + * Internal 1.56 + * collect_key 1.57 + * collect_data 1.58 + */ 1.59 + 1.60 +#if !defined(_WIN32) && !defined(_WINDOWS) && !defined(macintosh) 1.61 +#include <sys/param.h> 1.62 +#endif 1.63 + 1.64 +#include <errno.h> 1.65 +#include <stdio.h> 1.66 +#include <stdlib.h> 1.67 +#include <string.h> 1.68 + 1.69 +#ifdef DEBUG 1.70 +#include <assert.h> 1.71 +#endif 1.72 + 1.73 +#include "mcom_db.h" 1.74 +#include "hash.h" 1.75 +#include "page.h" 1.76 +/* #include "extern.h" */ 1.77 + 1.78 +static int collect_key __P((HTAB *, BUFHEAD *, int, DBT *, int)); 1.79 +static int collect_data __P((HTAB *, BUFHEAD *, int, int)); 1.80 + 1.81 +/* 1.82 + * Big_insert 1.83 + * 1.84 + * You need to do an insert and the key/data pair is too big 1.85 + * 1.86 + * Returns: 1.87 + * 0 ==> OK 1.88 + *-1 ==> ERROR 1.89 + */ 1.90 +extern int 1.91 +__big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val) 1.92 +{ 1.93 + register uint16 *p; 1.94 + uint key_size, n, val_size; 1.95 + uint16 space, move_bytes, off; 1.96 + char *cp, *key_data, *val_data; 1.97 + 1.98 + cp = bufp->page; /* Character pointer of p. */ 1.99 + p = (uint16 *)cp; 1.100 + 1.101 + key_data = (char *)key->data; 1.102 + key_size = key->size; 1.103 + val_data = (char *)val->data; 1.104 + val_size = val->size; 1.105 + 1.106 + /* First move the Key */ 1.107 + for (space = FREESPACE(p) - BIGOVERHEAD; key_size; 1.108 + space = FREESPACE(p) - BIGOVERHEAD) { 1.109 + move_bytes = PR_MIN(space, key_size); 1.110 + off = OFFSET(p) - move_bytes; 1.111 + memmove(cp + off, key_data, move_bytes); 1.112 + key_size -= move_bytes; 1.113 + key_data += move_bytes; 1.114 + n = p[0]; 1.115 + p[++n] = off; 1.116 + p[0] = ++n; 1.117 + FREESPACE(p) = off - PAGE_META(n); 1.118 + OFFSET(p) = off; 1.119 + p[n] = PARTIAL_KEY; 1.120 + bufp = __add_ovflpage(hashp, bufp); 1.121 + if (!bufp) 1.122 + return (-1); 1.123 + n = p[0]; 1.124 + if (!key_size) { 1.125 + if (FREESPACE(p)) { 1.126 + move_bytes = PR_MIN(FREESPACE(p), val_size); 1.127 + off = OFFSET(p) - move_bytes; 1.128 + p[n] = off; 1.129 + memmove(cp + off, val_data, move_bytes); 1.130 + val_data += move_bytes; 1.131 + val_size -= move_bytes; 1.132 + p[n - 2] = FULL_KEY_DATA; 1.133 + FREESPACE(p) = FREESPACE(p) - move_bytes; 1.134 + OFFSET(p) = off; 1.135 + } else 1.136 + p[n - 2] = FULL_KEY; 1.137 + } 1.138 + p = (uint16 *)bufp->page; 1.139 + cp = bufp->page; 1.140 + bufp->flags |= BUF_MOD; 1.141 + } 1.142 + 1.143 + /* Now move the data */ 1.144 + for (space = FREESPACE(p) - BIGOVERHEAD; val_size; 1.145 + space = FREESPACE(p) - BIGOVERHEAD) { 1.146 + move_bytes = PR_MIN(space, val_size); 1.147 + /* 1.148 + * Here's the hack to make sure that if the data ends on the 1.149 + * same page as the key ends, FREESPACE is at least one. 1.150 + */ 1.151 + if (space == val_size && val_size == val->size) 1.152 + move_bytes--; 1.153 + off = OFFSET(p) - move_bytes; 1.154 + memmove(cp + off, val_data, move_bytes); 1.155 + val_size -= move_bytes; 1.156 + val_data += move_bytes; 1.157 + n = p[0]; 1.158 + p[++n] = off; 1.159 + p[0] = ++n; 1.160 + FREESPACE(p) = off - PAGE_META(n); 1.161 + OFFSET(p) = off; 1.162 + if (val_size) { 1.163 + p[n] = FULL_KEY; 1.164 + bufp = __add_ovflpage(hashp, bufp); 1.165 + if (!bufp) 1.166 + return (-1); 1.167 + cp = bufp->page; 1.168 + p = (uint16 *)cp; 1.169 + } else 1.170 + p[n] = FULL_KEY_DATA; 1.171 + bufp->flags |= BUF_MOD; 1.172 + } 1.173 + return (0); 1.174 +} 1.175 + 1.176 +/* 1.177 + * Called when bufp's page contains a partial key (index should be 1) 1.178 + * 1.179 + * All pages in the big key/data pair except bufp are freed. We cannot 1.180 + * free bufp because the page pointing to it is lost and we can't get rid 1.181 + * of its pointer. 1.182 + * 1.183 + * Returns: 1.184 + * 0 => OK 1.185 + *-1 => ERROR 1.186 + */ 1.187 +extern int 1.188 +__big_delete(HTAB *hashp, BUFHEAD *bufp) 1.189 +{ 1.190 + register BUFHEAD *last_bfp, *rbufp; 1.191 + uint16 *bp, pageno; 1.192 + int key_done, n; 1.193 + 1.194 + rbufp = bufp; 1.195 + last_bfp = NULL; 1.196 + bp = (uint16 *)bufp->page; 1.197 + pageno = 0; 1.198 + key_done = 0; 1.199 + 1.200 + while (!key_done || (bp[2] != FULL_KEY_DATA)) { 1.201 + if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) 1.202 + key_done = 1; 1.203 + 1.204 + /* 1.205 + * If there is freespace left on a FULL_KEY_DATA page, then 1.206 + * the data is short and fits entirely on this page, and this 1.207 + * is the last page. 1.208 + */ 1.209 + if (bp[2] == FULL_KEY_DATA && FREESPACE(bp)) 1.210 + break; 1.211 + pageno = bp[bp[0] - 1]; 1.212 + rbufp->flags |= BUF_MOD; 1.213 + rbufp = __get_buf(hashp, pageno, rbufp, 0); 1.214 + if (last_bfp) 1.215 + __free_ovflpage(hashp, last_bfp); 1.216 + last_bfp = rbufp; 1.217 + if (!rbufp) 1.218 + return (-1); /* Error. */ 1.219 + bp = (uint16 *)rbufp->page; 1.220 + } 1.221 + 1.222 + /* 1.223 + * If we get here then rbufp points to the last page of the big 1.224 + * key/data pair. Bufp points to the first one -- it should now be 1.225 + * empty pointing to the next page after this pair. Can't free it 1.226 + * because we don't have the page pointing to it. 1.227 + */ 1.228 + 1.229 + /* This is information from the last page of the pair. */ 1.230 + n = bp[0]; 1.231 + pageno = bp[n - 1]; 1.232 + 1.233 + /* Now, bp is the first page of the pair. */ 1.234 + bp = (uint16 *)bufp->page; 1.235 + if (n > 2) { 1.236 + /* There is an overflow page. */ 1.237 + bp[1] = pageno; 1.238 + bp[2] = OVFLPAGE; 1.239 + bufp->ovfl = rbufp->ovfl; 1.240 + } else 1.241 + /* This is the last page. */ 1.242 + bufp->ovfl = NULL; 1.243 + n -= 2; 1.244 + bp[0] = n; 1.245 + FREESPACE(bp) = hashp->BSIZE - PAGE_META(n); 1.246 + OFFSET(bp) = hashp->BSIZE - 1; 1.247 + 1.248 + bufp->flags |= BUF_MOD; 1.249 + if (rbufp) 1.250 + __free_ovflpage(hashp, rbufp); 1.251 + if (last_bfp != rbufp) 1.252 + __free_ovflpage(hashp, last_bfp); 1.253 + 1.254 + hashp->NKEYS--; 1.255 + return (0); 1.256 +} 1.257 +/* 1.258 + * Returns: 1.259 + * 0 = key not found 1.260 + * -1 = get next overflow page 1.261 + * -2 means key not found and this is big key/data 1.262 + * -3 error 1.263 + */ 1.264 +extern int 1.265 +__find_bigpair(HTAB *hashp, BUFHEAD *bufp, int ndx, char *key, int size) 1.266 +{ 1.267 + register uint16 *bp; 1.268 + register char *p; 1.269 + int ksize; 1.270 + uint16 bytes; 1.271 + char *kkey; 1.272 + 1.273 + bp = (uint16 *)bufp->page; 1.274 + p = bufp->page; 1.275 + ksize = size; 1.276 + kkey = key; 1.277 + 1.278 + for (bytes = hashp->BSIZE - bp[ndx]; 1.279 + bytes <= size && bp[ndx + 1] == PARTIAL_KEY; 1.280 + bytes = hashp->BSIZE - bp[ndx]) { 1.281 + if (memcmp(p + bp[ndx], kkey, bytes)) 1.282 + return (-2); 1.283 + kkey += bytes; 1.284 + ksize -= bytes; 1.285 + bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0); 1.286 + if (!bufp) 1.287 + return (-3); 1.288 + p = bufp->page; 1.289 + bp = (uint16 *)p; 1.290 + ndx = 1; 1.291 + } 1.292 + 1.293 + if (bytes != ksize || memcmp(p + bp[ndx], kkey, bytes)) { 1.294 +#ifdef HASH_STATISTICS 1.295 + ++hash_collisions; 1.296 +#endif 1.297 + return (-2); 1.298 + } else 1.299 + return (ndx); 1.300 +} 1.301 + 1.302 +/* 1.303 + * Given the buffer pointer of the first overflow page of a big pair, 1.304 + * find the end of the big pair 1.305 + * 1.306 + * This will set bpp to the buffer header of the last page of the big pair. 1.307 + * It will return the pageno of the overflow page following the last page 1.308 + * of the pair; 0 if there isn't any (i.e. big pair is the last key in the 1.309 + * bucket) 1.310 + */ 1.311 +extern uint16 1.312 +__find_last_page(HTAB *hashp, BUFHEAD **bpp) 1.313 +{ 1.314 + BUFHEAD *bufp; 1.315 + uint16 *bp, pageno; 1.316 + uint n; 1.317 + 1.318 + bufp = *bpp; 1.319 + bp = (uint16 *)bufp->page; 1.320 + for (;;) { 1.321 + n = bp[0]; 1.322 + 1.323 + /* 1.324 + * This is the last page if: the tag is FULL_KEY_DATA and 1.325 + * either only 2 entries OVFLPAGE marker is explicit there 1.326 + * is freespace on the page. 1.327 + */ 1.328 + if (bp[2] == FULL_KEY_DATA && 1.329 + ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)))) 1.330 + break; 1.331 + 1.332 + /* LJM bound the size of n to reasonable limits 1.333 + */ 1.334 + if(n > hashp->BSIZE/sizeof(uint16)) 1.335 + return(0); 1.336 + 1.337 + pageno = bp[n - 1]; 1.338 + bufp = __get_buf(hashp, pageno, bufp, 0); 1.339 + if (!bufp) 1.340 + return (0); /* Need to indicate an error! */ 1.341 + bp = (uint16 *)bufp->page; 1.342 + } 1.343 + 1.344 + *bpp = bufp; 1.345 + if (bp[0] > 2) 1.346 + return (bp[3]); 1.347 + else 1.348 + return (0); 1.349 +} 1.350 + 1.351 +/* 1.352 + * Return the data for the key/data pair that begins on this page at this 1.353 + * index (index should always be 1). 1.354 + */ 1.355 +extern int 1.356 +__big_return( 1.357 + HTAB *hashp, 1.358 + BUFHEAD *bufp, 1.359 + int ndx, 1.360 + DBT *val, 1.361 + int set_current) 1.362 +{ 1.363 + BUFHEAD *save_p; 1.364 + uint16 *bp, len, off, save_addr; 1.365 + char *tp; 1.366 + int save_flags; 1.367 + 1.368 + bp = (uint16 *)bufp->page; 1.369 + while (bp[ndx + 1] == PARTIAL_KEY) { 1.370 + bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 1.371 + if (!bufp) 1.372 + return (-1); 1.373 + bp = (uint16 *)bufp->page; 1.374 + ndx = 1; 1.375 + } 1.376 + 1.377 + if (bp[ndx + 1] == FULL_KEY) { 1.378 + bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 1.379 + if (!bufp) 1.380 + return (-1); 1.381 + bp = (uint16 *)bufp->page; 1.382 + save_p = bufp; 1.383 + save_addr = save_p->addr; 1.384 + off = bp[1]; 1.385 + len = 0; 1.386 + } else 1.387 + if (!FREESPACE(bp)) { 1.388 + /* 1.389 + * This is a hack. We can't distinguish between 1.390 + * FULL_KEY_DATA that contains complete data or 1.391 + * incomplete data, so we require that if the data 1.392 + * is complete, there is at least 1 byte of free 1.393 + * space left. 1.394 + */ 1.395 + off = bp[bp[0]]; 1.396 + len = bp[1] - off; 1.397 + save_p = bufp; 1.398 + save_addr = bufp->addr; 1.399 + bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 1.400 + if (!bufp) 1.401 + return (-1); 1.402 + bp = (uint16 *)bufp->page; 1.403 + } else { 1.404 + /* The data is all on one page. */ 1.405 + tp = (char *)bp; 1.406 + off = bp[bp[0]]; 1.407 + val->data = (uint8 *)tp + off; 1.408 + val->size = bp[1] - off; 1.409 + if (set_current) { 1.410 + if (bp[0] == 2) { /* No more buckets in 1.411 + * chain */ 1.412 + hashp->cpage = NULL; 1.413 + hashp->cbucket++; 1.414 + hashp->cndx = 1; 1.415 + } else { 1.416 + hashp->cpage = __get_buf(hashp, 1.417 + bp[bp[0] - 1], bufp, 0); 1.418 + if (!hashp->cpage) 1.419 + return (-1); 1.420 + hashp->cndx = 1; 1.421 + if (!((uint16 *) 1.422 + hashp->cpage->page)[0]) { 1.423 + hashp->cbucket++; 1.424 + hashp->cpage = NULL; 1.425 + } 1.426 + } 1.427 + } 1.428 + return (0); 1.429 + } 1.430 + 1.431 + /* pin our saved buf so that we don't lose if 1.432 + * we run out of buffers */ 1.433 + save_flags = save_p->flags; 1.434 + save_p->flags |= BUF_PIN; 1.435 + val->size = collect_data(hashp, bufp, (int)len, set_current); 1.436 + save_p->flags = save_flags; 1.437 + if (val->size == (size_t)-1) 1.438 + return (-1); 1.439 + if (save_p->addr != save_addr) { 1.440 + /* We are pretty short on buffers. */ 1.441 + errno = EINVAL; /* OUT OF BUFFERS */ 1.442 + return (-1); 1.443 + } 1.444 + memmove(hashp->tmp_buf, (save_p->page) + off, len); 1.445 + val->data = (uint8 *)hashp->tmp_buf; 1.446 + return (0); 1.447 +} 1.448 + 1.449 + 1.450 +/* 1.451 + * Count how big the total datasize is by looping through the pages. Then 1.452 + * allocate a buffer and copy the data in the second loop. NOTE: Our caller 1.453 + * may already have a bp which it is holding onto. The caller is 1.454 + * responsible for copying that bp into our temp buffer. 'len' is how much 1.455 + * space to reserve for that buffer. 1.456 + */ 1.457 +static int 1.458 +collect_data( 1.459 + HTAB *hashp, 1.460 + BUFHEAD *bufp, 1.461 + int len, int set) 1.462 +{ 1.463 + register uint16 *bp; 1.464 + BUFHEAD *save_bufp; 1.465 + int save_flags; 1.466 + int mylen, totlen; 1.467 + 1.468 + /* 1.469 + * save the input buf head because we need to walk the list twice. 1.470 + * pin it to make sure it doesn't leave the buffer pool. 1.471 + * This has the effect of growing the buffer pool if necessary. 1.472 + */ 1.473 + save_bufp = bufp; 1.474 + save_flags = save_bufp->flags; 1.475 + save_bufp->flags |= BUF_PIN; 1.476 + 1.477 + /* read the length of the buffer */ 1.478 + for (totlen = len; bufp ; bufp = __get_buf(hashp, bp[bp[0]-1], bufp, 0)) { 1.479 + bp = (uint16 *)bufp->page; 1.480 + mylen = hashp->BSIZE - bp[1]; 1.481 + 1.482 + /* if mylen ever goes negative it means that the 1.483 + * page is screwed up. 1.484 + */ 1.485 + if (mylen < 0) { 1.486 + save_bufp->flags = save_flags; 1.487 + return (-1); 1.488 + } 1.489 + totlen += mylen; 1.490 + if (bp[2] == FULL_KEY_DATA) { /* End of Data */ 1.491 + break; 1.492 + } 1.493 + } 1.494 + 1.495 + if (!bufp) { 1.496 + save_bufp->flags = save_flags; 1.497 + return (-1); 1.498 + } 1.499 + 1.500 + /* allocate a temp buf */ 1.501 + if (hashp->tmp_buf) 1.502 + free(hashp->tmp_buf); 1.503 + if ((hashp->tmp_buf = (char *)malloc((size_t)totlen)) == NULL) { 1.504 + save_bufp->flags = save_flags; 1.505 + return (-1); 1.506 + } 1.507 + 1.508 + /* copy the buffers back into temp buf */ 1.509 + for (bufp = save_bufp; bufp ; 1.510 + bufp = __get_buf(hashp, bp[bp[0]-1], bufp, 0)) { 1.511 + bp = (uint16 *)bufp->page; 1.512 + mylen = hashp->BSIZE - bp[1]; 1.513 + memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], (size_t)mylen); 1.514 + len += mylen; 1.515 + if (bp[2] == FULL_KEY_DATA) { 1.516 + break; 1.517 + } 1.518 + } 1.519 + 1.520 + /* 'clear' the pin flags */ 1.521 + save_bufp->flags = save_flags; 1.522 + 1.523 + /* update the database cursor */ 1.524 + if (set) { 1.525 + hashp->cndx = 1; 1.526 + if (bp[0] == 2) { /* No more buckets in chain */ 1.527 + hashp->cpage = NULL; 1.528 + hashp->cbucket++; 1.529 + } else { 1.530 + hashp->cpage = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 1.531 + if (!hashp->cpage) 1.532 + return (-1); 1.533 + else if (!((uint16 *)hashp->cpage->page)[0]) { 1.534 + hashp->cbucket++; 1.535 + hashp->cpage = NULL; 1.536 + } 1.537 + } 1.538 + } 1.539 + return (totlen); 1.540 +} 1.541 + 1.542 +/* 1.543 + * Fill in the key and data for this big pair. 1.544 + */ 1.545 +extern int 1.546 +__big_keydata( 1.547 + HTAB *hashp, 1.548 + BUFHEAD *bufp, 1.549 + DBT *key, DBT *val, 1.550 + int set) 1.551 +{ 1.552 + key->size = collect_key(hashp, bufp, 0, val, set); 1.553 + if (key->size == (size_t)-1) 1.554 + return (-1); 1.555 + key->data = (uint8 *)hashp->tmp_key; 1.556 + return (0); 1.557 +} 1.558 + 1.559 +/* 1.560 + * Count how big the total key size is by recursing through the pages. Then 1.561 + * collect the data, allocate a buffer and copy the key as you recurse up. 1.562 + */ 1.563 +static int 1.564 +collect_key( 1.565 + HTAB *hashp, 1.566 + BUFHEAD *bufp, 1.567 + int len, 1.568 + DBT *val, 1.569 + int set) 1.570 +{ 1.571 + BUFHEAD *xbp; 1.572 + char *p; 1.573 + int mylen, totlen; 1.574 + uint16 *bp, save_addr; 1.575 + 1.576 + p = bufp->page; 1.577 + bp = (uint16 *)p; 1.578 + mylen = hashp->BSIZE - bp[1]; 1.579 + 1.580 + save_addr = bufp->addr; 1.581 + totlen = len + mylen; 1.582 + if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */ 1.583 + if (hashp->tmp_key != NULL) 1.584 + free(hashp->tmp_key); 1.585 + if ((hashp->tmp_key = (char *)malloc((size_t)totlen)) == NULL) 1.586 + return (-1); 1.587 + if (__big_return(hashp, bufp, 1, val, set)) 1.588 + return (-1); 1.589 + } else { 1.590 + xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0); 1.591 + if (!xbp || ((totlen = 1.592 + collect_key(hashp, xbp, totlen, val, set)) < 1)) 1.593 + return (-1); 1.594 + } 1.595 + if (bufp->addr != save_addr) { 1.596 + errno = EINVAL; /* MIS -- OUT OF BUFFERS */ 1.597 + return (-1); 1.598 + } 1.599 + memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], (size_t)mylen); 1.600 + return (totlen); 1.601 +} 1.602 + 1.603 +/* 1.604 + * Returns: 1.605 + * 0 => OK 1.606 + * -1 => error 1.607 + */ 1.608 +extern int 1.609 +__big_split( 1.610 + HTAB *hashp, 1.611 + BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */ 1.612 + BUFHEAD *np, /* Pointer to new bucket page */ 1.613 + /* Pointer to first page containing the big key/data */ 1.614 + BUFHEAD *big_keyp, 1.615 + uint32 addr, /* Address of big_keyp */ 1.616 + uint32 obucket,/* Old Bucket */ 1.617 + SPLIT_RETURN *ret) 1.618 +{ 1.619 + register BUFHEAD *tmpp; 1.620 + register uint16 *tp; 1.621 + BUFHEAD *bp; 1.622 + DBT key, val; 1.623 + uint32 change; 1.624 + uint16 free_space, n, off; 1.625 + 1.626 + bp = big_keyp; 1.627 + 1.628 + /* Now figure out where the big key/data goes */ 1.629 + if (__big_keydata(hashp, big_keyp, &key, &val, 0)) 1.630 + return (-1); 1.631 + change = (__call_hash(hashp,(char*) key.data, key.size) != obucket); 1.632 + 1.633 + if ((ret->next_addr = __find_last_page(hashp, &big_keyp))) { 1.634 + if (!(ret->nextp = 1.635 + __get_buf(hashp, ret->next_addr, big_keyp, 0))) 1.636 + return (-1);; 1.637 + } else 1.638 + ret->nextp = NULL; 1.639 + 1.640 + /* Now make one of np/op point to the big key/data pair */ 1.641 +#ifdef DEBUG 1.642 + assert(np->ovfl == NULL); 1.643 +#endif 1.644 + if (change) 1.645 + tmpp = np; 1.646 + else 1.647 + tmpp = op; 1.648 + 1.649 + tmpp->flags |= BUF_MOD; 1.650 +#ifdef DEBUG1 1.651 + (void)fprintf(stderr, 1.652 + "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr, 1.653 + (tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0)); 1.654 +#endif 1.655 + tmpp->ovfl = bp; /* one of op/np point to big_keyp */ 1.656 + tp = (uint16 *)tmpp->page; 1.657 + 1.658 + 1.659 +#if 0 /* this get's tripped on database corrupted error */ 1.660 + assert(FREESPACE(tp) >= OVFLSIZE); 1.661 +#endif 1.662 + if(FREESPACE(tp) < OVFLSIZE) 1.663 + return(DATABASE_CORRUPTED_ERROR); 1.664 + 1.665 + n = tp[0]; 1.666 + off = OFFSET(tp); 1.667 + free_space = FREESPACE(tp); 1.668 + tp[++n] = (uint16)addr; 1.669 + tp[++n] = OVFLPAGE; 1.670 + tp[0] = n; 1.671 + OFFSET(tp) = off; 1.672 + FREESPACE(tp) = free_space - OVFLSIZE; 1.673 + 1.674 + /* 1.675 + * Finally, set the new and old return values. BIG_KEYP contains a 1.676 + * pointer to the last page of the big key_data pair. Make sure that 1.677 + * big_keyp has no following page (2 elements) or create an empty 1.678 + * following page. 1.679 + */ 1.680 + 1.681 + ret->newp = np; 1.682 + ret->oldp = op; 1.683 + 1.684 + tp = (uint16 *)big_keyp->page; 1.685 + big_keyp->flags |= BUF_MOD; 1.686 + if (tp[0] > 2) { 1.687 + /* 1.688 + * There may be either one or two offsets on this page. If 1.689 + * there is one, then the overflow page is linked on normally 1.690 + * and tp[4] is OVFLPAGE. If there are two, tp[4] contains 1.691 + * the second offset and needs to get stuffed in after the 1.692 + * next overflow page is added. 1.693 + */ 1.694 + n = tp[4]; 1.695 + free_space = FREESPACE(tp); 1.696 + off = OFFSET(tp); 1.697 + tp[0] -= 2; 1.698 + FREESPACE(tp) = free_space + OVFLSIZE; 1.699 + OFFSET(tp) = off; 1.700 + tmpp = __add_ovflpage(hashp, big_keyp); 1.701 + if (!tmpp) 1.702 + return (-1); 1.703 + tp[4] = n; 1.704 + } else 1.705 + tmpp = big_keyp; 1.706 + 1.707 + if (change) 1.708 + ret->newp = tmpp; 1.709 + else 1.710 + ret->oldp = tmpp; 1.711 + return (0); 1.712 +}