1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include "synonyms.h" 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <fcntl.h> 46 #include <sys/file.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <errno.h> 50 #include <ndbm.h> 51 #include <unistd.h> 52 #include <string.h> 53 #include <pthread.h> 54 55 /* add support for batched writing for NIS */ 56 57 #define _DBM_DEFWRITE 0x4 58 #define _DBM_DIRTY 0x8 59 #define _DBM_DIRDIRTY 0x10 60 #define dbm_dirty(db) ((db)->dbm_flags & _DBM_DIRTY) 61 #define dbm_dirdirty(db) ((db)->dbm_flags & _DBM_DIRDIRTY) 62 #define dbm_defwrite(db) ((db)->dbm_flags & _DBM_DEFWRITE) 63 #define dbm_setdirty(db) (db)->dbm_flags |= _DBM_DIRTY 64 #define dbm_clrdirty(db) (db)->dbm_flags &= ~_DBM_DIRTY 65 #define dbm_setdirdirty(db) (db)->dbm_flags |= _DBM_DIRDIRTY 66 #define dbm_clrdirdirty(db) (db)->dbm_flags &= ~_DBM_DIRDIRTY 67 68 /* 69 * forward declarations 70 */ 71 static datum makdatum(char *, int); 72 static unsigned long dcalchash(datum); 73 static void dbm_access(DBM *, unsigned long); 74 static int finddatum(char *, datum); 75 static int delitem(char *, int); 76 static int additem(char *, datum, datum); 77 static int cmpdatum(datum, datum); 78 static int setbit(DBM *); 79 static int getbit(DBM *); 80 static int dbm_flushdir(DBM *); 81 static int dbm_flushpag(DBM *db); 82 83 /* the following three are required by mapfile-vers */ 84 datum dbm_do_nextkey(DBM *, datum); 85 int dbm_close_status(DBM *); 86 87 /* used to make a dbm file all at once instead of incrementally */ 88 void 89 dbm_setdefwrite(DBM *db) 90 { 91 db->dbm_flags |= _DBM_DEFWRITE; 92 } 93 94 #undef dbm_error 95 96 int 97 dbm_error(DBM *db) 98 { 99 return (db->dbm_flags & _DBM_IOERR); 100 } 101 102 #undef dbm_clearerr 103 104 int 105 dbm_clearerr(DBM *db) 106 { 107 return (db->dbm_flags &= ~_DBM_IOERR); 108 } 109 110 int 111 dbm_flush(DBM *db) 112 { 113 int ok = 0; 114 if (dbm_flushpag(db) < 0) 115 ok = -1; 116 if (dbm_flushdir(db) < 0) 117 ok = -1; 118 return (ok); 119 } 120 121 static int 122 dbm_flushpag(DBM *db) 123 { 124 int ok = 0; 125 off64_t where; 126 127 if (dbm_dirty(db)) { /* must page out the page */ 128 where = (((off64_t)db->dbm_pagbno) * PBLKSIZ); 129 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 130 (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ)) { 131 db->dbm_flags |= _DBM_IOERR; 132 ok = -1; 133 } 134 dbm_clrdirty(db); 135 } 136 return (ok); 137 } 138 139 static int 140 dbm_flushdir(DBM *db) 141 { 142 int ok = 0; 143 off64_t where; 144 if (dbm_dirdirty(db)) { /* must page out the dir */ 145 where = (((off64_t)db->dbm_dirbno) * DBLKSIZ); 146 if ((lseek64(db->dbm_dirf, where, L_SET) != where) || 147 (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ)) { 148 ok = -1; 149 } 150 dbm_clrdirdirty(db); 151 } 152 return (ok); 153 } 154 155 #define BYTESIZ 8 156 #undef setbit 157 158 DBM * 159 dbm_open(const char *file, int flags, mode_t mode) 160 { 161 struct stat64 statb; 162 DBM *db; 163 int serrno; 164 165 if ((db = (DBM *)malloc(sizeof (*db))) == 0) { 166 errno = ENOMEM; 167 return ((DBM *)0); 168 } 169 db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; 170 if ((flags & 03) == O_WRONLY) 171 flags = (flags & ~03) | O_RDWR; 172 if (strlcpy(db->dbm_pagbuf, file, sizeof (db->dbm_pagbuf)) >= 173 sizeof (db->dbm_pagbuf) || 174 strlcat(db->dbm_pagbuf, ".pag", sizeof (db->dbm_pagbuf)) >= 175 sizeof (db->dbm_pagbuf)) { 176 /* 177 * file.pag does not fit into dbm_pagbuf. 178 * fail with ENAMETOOLONG. 179 */ 180 serrno = ENAMETOOLONG; 181 goto bad; 182 } 183 db->dbm_pagf = open64(db->dbm_pagbuf, flags, mode); 184 if (db->dbm_pagf < 0) { 185 serrno = errno; 186 goto bad; 187 } 188 /* 189 * We know this won't overflow so it is safe to ignore the 190 * return value; we use strl* to prevent false hits in 191 * code sweeps. 192 */ 193 (void) strlcpy(db->dbm_pagbuf, file, sizeof (db->dbm_pagbuf)); 194 (void) strlcat(db->dbm_pagbuf, ".dir", sizeof (db->dbm_pagbuf)); 195 db->dbm_dirf = open64(db->dbm_pagbuf, flags, mode); 196 if (db->dbm_dirf < 0) { 197 serrno = errno; 198 goto bad1; 199 } 200 (void) fstat64(db->dbm_dirf, &statb); 201 db->dbm_maxbno = statb.st_size * BYTESIZ-1; 202 db->dbm_pagbno = db->dbm_dirbno = -1; 203 return (db); 204 bad1: 205 (void) close(db->dbm_pagf); 206 bad: 207 free((char *)db); 208 errno = serrno; 209 return ((DBM *)0); 210 } 211 212 void 213 dbm_close(DBM *db) 214 { 215 (void) dbm_close_status(db); 216 } 217 218 /* close with return code */ 219 int 220 dbm_close_status(DBM *db) 221 { 222 int ok; 223 ok = 0; 224 225 if (dbm_flush(db) < 0) 226 ok = -1; 227 if (close(db->dbm_dirf) < 0) 228 ok = -1; 229 if (close(db->dbm_pagf) < 0) 230 ok = -1; 231 free((char *)db); 232 return (ok); 233 } 234 235 long 236 dbm_forder(DBM *db, datum key) 237 { 238 unsigned long hash; 239 240 hash = dcalchash(key); 241 for (db->dbm_hmask = 0; ; db->dbm_hmask = (db->dbm_hmask<<1)+1) { 242 db->dbm_blkno = hash & db->dbm_hmask; 243 db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 244 if (getbit(db) == 0) 245 break; 246 } 247 return (db->dbm_blkno); 248 } 249 250 datum 251 dbm_fetch(DBM *db, datum key) 252 { 253 int i; 254 datum item; 255 256 if (dbm_error(db)) 257 goto err; 258 dbm_access(db, dcalchash(key)); 259 if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 260 item = makdatum(db->dbm_pagbuf, i+1); 261 if (item.dptr != NULL) 262 return (item); 263 } 264 err: 265 item.dptr = NULL; 266 item.dsize = 0; 267 return (item); 268 } 269 270 int 271 dbm_delete(DBM *db, datum key) 272 { 273 int i; 274 off64_t where; 275 276 if (dbm_error(db)) 277 return (-1); 278 if (dbm_rdonly(db)) { 279 errno = EPERM; 280 return (-1); 281 } 282 dbm_access(db, dcalchash(key)); 283 if ((i = finddatum(db->dbm_pagbuf, key)) < 0) 284 return (-1); 285 if (!delitem(db->dbm_pagbuf, i)) 286 goto err; 287 db->dbm_pagbno = db->dbm_blkno; 288 if (dbm_defwrite(db)) { 289 dbm_setdirty(db); 290 } else { 291 where = (((off64_t)db->dbm_blkno) * PBLKSIZ); 292 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 293 (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ)) { 294 err: 295 db->dbm_flags |= _DBM_IOERR; 296 return (-1); 297 } 298 } 299 return (0); 300 } 301 302 int 303 dbm_store(DBM *db, datum key, datum dat, int replace) 304 { 305 int i; 306 datum item, item1; 307 char ovfbuf[PBLKSIZ]; 308 unsigned long hashdiff, key_hash, item_hash; 309 off64_t where; 310 311 if (dbm_error(db)) 312 return (-1); 313 if (dbm_rdonly(db)) { 314 errno = EPERM; 315 return (-1); 316 } 317 loop: 318 key_hash = dcalchash(key); 319 dbm_access(db, key_hash); 320 if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 321 if (!replace) 322 return (1); 323 if (!delitem(db->dbm_pagbuf, i)) { 324 db->dbm_flags |= _DBM_IOERR; 325 return (-1); 326 } 327 } 328 if (!additem(db->dbm_pagbuf, key, dat)) 329 goto split; 330 db->dbm_pagbno = db->dbm_blkno; 331 if (dbm_defwrite(db)) { 332 dbm_setdirty(db); 333 } else { 334 where = (((off64_t)db->dbm_blkno) * PBLKSIZ); 335 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 336 (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ)) { 337 db->dbm_flags |= _DBM_IOERR; 338 return (-1); 339 } 340 } 341 return (0); 342 split: 343 hashdiff = 0; 344 if (key.dsize + dat.dsize + 3 * (int)sizeof (short) >= PBLKSIZ) { 345 db->dbm_flags |= _DBM_IOERR; 346 errno = ENOSPC; 347 return (-1); 348 } 349 (void) memset(ovfbuf, 0, PBLKSIZ); 350 for (i = 0; ; ) { 351 item = makdatum(db->dbm_pagbuf, i); 352 if (item.dptr == NULL) 353 break; 354 item_hash = dcalchash(item); 355 if (item_hash != key_hash) { 356 hashdiff++; 357 } 358 359 if (item_hash & (db->dbm_hmask+1)) { 360 item1 = makdatum(db->dbm_pagbuf, i+1); 361 if (item1.dptr == NULL) { 362 /* (void) fprintf(stderr, "ndbm: */ 363 /* split not paired\n"); */ 364 db->dbm_flags |= _DBM_IOERR; 365 break; 366 } 367 if (!additem(ovfbuf, item, item1) || 368 !delitem(db->dbm_pagbuf, i)) { 369 db->dbm_flags |= _DBM_IOERR; 370 return (-1); 371 } 372 continue; 373 } 374 i += 2; 375 } 376 db->dbm_pagbno = db->dbm_blkno; 377 where = (((off64_t)db->dbm_blkno) * PBLKSIZ); 378 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 379 (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ)) { 380 db->dbm_flags |= _DBM_IOERR; 381 return (-1); 382 } 383 dbm_clrdirty(db); /* clear dirty */ 384 where = (((off64_t)db->dbm_blkno + db->dbm_hmask + 1) * PBLKSIZ); 385 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 386 (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ)) { 387 db->dbm_flags |= _DBM_IOERR; 388 return (-1); 389 } 390 if (setbit(db) < 0) { 391 db->dbm_flags |= _DBM_IOERR; 392 return (-1); 393 } 394 if (hashdiff == 0) { 395 db->dbm_flags |= _DBM_IOERR; 396 return (-1); 397 } 398 goto loop; 399 } 400 401 static unsigned long 402 dbm_hashinc(DBM *db, unsigned long hash) 403 { 404 long bit; 405 406 hash &= db->dbm_hmask; 407 bit = db->dbm_hmask+1; 408 for (;;) { 409 bit >>= 1; 410 if (bit == 0) 411 return (0L); 412 if ((hash&bit) == 0) 413 return (hash|bit); 414 hash &= ~bit; 415 } 416 } 417 418 419 420 static datum nullkey = {NULL, 0}; 421 422 datum 423 dbm_firsthash(DBM *db, unsigned long hash) 424 { 425 int i, j; 426 datum item, bitem; 427 428 loop: 429 dbm_access(db, hash); 430 j = 0; 431 bitem = makdatum(db->dbm_pagbuf, 0); 432 for (i = 2; ; i += 2) { 433 item = makdatum(db->dbm_pagbuf, i); 434 if (item.dptr == NULL) 435 break; 436 if (cmpdatum(bitem, item) < 0) { 437 j = i; 438 bitem = item; 439 } 440 } 441 if (bitem.dptr != NULL) { 442 db->dbm_keyptr = j + 2; 443 db->dbm_blkptr = db->dbm_blkno; 444 return (bitem); 445 } 446 hash = dbm_hashinc(db, hash); 447 if (hash == 0) 448 return (item); /* null item */ 449 goto loop; 450 451 } 452 453 datum 454 dbm_firstkey(DBM *db) 455 { 456 /* 457 * For some reason, the Posix specification (SUSv3) 458 * says that dbm_firstkey() is not a cancellation point. 459 * It really should be, but in order to pass the SUSv3 460 * test suite we make it not a cancellation point. 461 * XXX: fix me when the SUSv3 specification gets fixed. 462 */ 463 int cancel_state; 464 datum rval; 465 466 db->dbm_blkptr = 0L; 467 db->dbm_keyptr = 0; 468 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); 469 rval = dbm_firsthash(db, 0L); 470 (void) pthread_setcancelstate(cancel_state, NULL); 471 return (rval); 472 } 473 474 datum 475 dbm_nextkey(DBM *db) 476 { 477 478 return (dbm_do_nextkey(db, nullkey)); 479 } 480 481 /* 482 * this is used if keyptr-2, blocknum doesn't point to the previous 483 * specific key allowing the fast hash order search -- 484 * its use indicates user tampering with our state variables, 485 * which some evil users might do to search from some specific place. 486 * It finds the first key at or after blkptr, keyptr in block seq order 487 * this requires looking at all sorts of emtpy blocks in many cases 488 */ 489 490 static 491 datum 492 dbm_slow_nextkey(DBM *db) 493 { 494 495 struct stat64 statb; 496 datum item; 497 off64_t where; 498 499 if (dbm_error(db) || fstat64(db->dbm_pagf, &statb) < 0) 500 goto err; 501 statb.st_size /= PBLKSIZ; 502 503 for (;;) { 504 if (db->dbm_blkptr != db->dbm_pagbno) { 505 506 if (dbm_dirty(db)) (void) dbm_flushpag(db); 507 508 db->dbm_pagbno = db->dbm_blkptr; 509 where = (((off64_t)db->dbm_blkptr) * PBLKSIZ); 510 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 511 (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != 512 PBLKSIZ)) 513 (void) memset(db->dbm_pagbuf, 0, PBLKSIZ); 514 #ifdef DEBUG 515 else if (chkblk(db->dbm_pagbuf) < 0) 516 db->dbm_flags |= _DBM_IOERR; 517 #endif 518 } 519 /* Am I an empty block? */ 520 if (((short *)(uintptr_t)db->dbm_pagbuf)[0] != 0) { 521 item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); 522 if (item.dptr != NULL) { 523 db->dbm_keyptr += 2; 524 return (item); 525 } 526 db->dbm_keyptr = 0; 527 } 528 /* go to next sequential block */ 529 if (++db->dbm_blkptr >= statb.st_size) 530 break; 531 } 532 err: 533 item.dptr = NULL; 534 item.dsize = 0; 535 return (item); 536 } 537 538 539 540 datum 541 dbm_do_nextkey(DBM *db, datum inkey) 542 { 543 datum item, bitem; 544 unsigned long hash; 545 datum key; 546 int f; 547 int i; 548 int j; 549 short *sp; 550 long n; 551 char *p1, *p2; 552 off64_t where; 553 554 if (dbm_error(db)) { 555 item.dptr = NULL; 556 item.dsize = 0; 557 return (item); 558 } 559 560 /* user has supplied lastkey */ 561 562 if (inkey.dptr != NULL) { 563 dbm_access(db, (hash = dcalchash(inkey))); 564 if ((i = finddatum(db->dbm_pagbuf, inkey)) >= 0) { 565 db->dbm_keyptr = i + 2; 566 db->dbm_blkptr = db->dbm_blkno; 567 } 568 key = inkey; 569 } else { 570 /* is this a manual firstkey request? */ 571 572 if (db->dbm_blkptr == 0L && 573 db->dbm_keyptr == 0) 574 return (dbm_firsthash(db, 0L)); 575 576 /* no -- get lastkey this is like dbm_access by blkptr */ 577 578 if (db->dbm_blkptr != db->dbm_pagbno) { 579 580 if (dbm_dirty(db)) (void) dbm_flushpag(db); 581 db->dbm_pagbno = db->dbm_blkptr; 582 where = (((off64_t)db->dbm_blkptr) * PBLKSIZ); 583 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 584 (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != 585 PBLKSIZ)) 586 (void) memset(db->dbm_pagbuf, 0, PBLKSIZ); 587 #ifdef DEBUG 588 else if (chkblk(db->dbm_pagbuf) < 0) 589 db->dbm_flags |= _DBM_IOERR; 590 #endif 591 } 592 /* now just make up last key datum */ 593 if (db->dbm_keyptr >= 2) 594 key = makdatum(db->dbm_pagbuf, (db->dbm_keyptr-2)); 595 else key = nullkey; 596 597 /* 598 * the keyptr pagbuf have failed us, the user must 599 * be an extra clever moron who depends on 600 * these variables and their former meaning. 601 * If we set the variables this would have got 602 * us the key for sure! So give him the old algorithm. 603 */ 604 if (key.dptr == NULL) 605 return (dbm_slow_nextkey(db)); 606 } 607 608 /* 609 * at this point the last key is paged in and 610 * we can proceed as in old dbm -- like Ken did his. 611 */ 612 613 f = 1; 614 j = 0; 615 sp = (short *)(uintptr_t)db->dbm_pagbuf; 616 617 for (i = 0; ; i += 2) { 618 619 /* begin put makdatum inline */ 620 621 if ((unsigned)i >= sp[0]) { 622 item.dptr = NULL; 623 item.dsize = 0; 624 break; /* from below */ 625 } else { 626 if (i > 0) item.dsize = sp[i] - sp[i + 1]; 627 else item.dsize = PBLKSIZ - sp[i + 1]; 628 item.dptr = db->dbm_pagbuf+sp[i + 1]; 629 } 630 631 /* item = makdatum(db->dbm_pagbuf, i); */ 632 /* end put makdatum inline */ 633 634 if (item.dptr == NULL) 635 break; 636 /* inline cmpdatum */ 637 638 639 n = key.dsize; 640 if (n != item.dsize) { 641 if ((n - item.dsize) <= 0) 642 continue; 643 } else { 644 if (n == 0) continue; 645 p1 = key.dptr; 646 p2 = item.dptr; 647 do { 648 if (*p1++ != *p2++) 649 if ((*--p1 - *--p2) > 0) 650 goto keep_going; 651 else continue; 652 } while (--n); 653 continue; 654 } 655 656 keep_going: 657 658 /* end inline cmpdatum */ 659 /* 660 * if (cmpdatum(key, item) <= 0) 661 * continue; 662 */ 663 664 if (f) { 665 bitem = item; 666 j = i; 667 f = 0; 668 } else { 669 670 /* if (cmpdatum(bitem, item) < 0) */ 671 672 n = bitem.dsize; 673 if (n != item.dsize) { 674 if ((n - item.dsize) < 0) { 675 bitem = item; 676 j = i; 677 } 678 } else 679 if (n != 0) { 680 p1 = bitem.dptr; 681 p2 = item.dptr; 682 do { 683 if (*p1++ != *p2++) { 684 if ((*--p1 - *--p2) < 0) { 685 bitem = item; 686 j = i; 687 } 688 break; 689 } 690 } while (--n); 691 } 692 } 693 } 694 695 if (f == 0) { 696 db->dbm_keyptr = j + 2; 697 db->dbm_blkptr = db->dbm_blkno; 698 return (bitem); 699 } 700 701 /* really need hash at this point */ 702 /* if he gave us a key we have already calculated the hash */ 703 /* if not get it */ 704 if (inkey.dptr == NULL) 705 hash = dcalchash(key); 706 hash = dbm_hashinc(db, hash); 707 708 if (hash == 0) 709 return (item); /* null */ 710 /* get first item on next page in hash table order */ 711 return (dbm_firsthash(db, hash)); 712 713 714 } 715 716 static void 717 dbm_access(DBM *db, unsigned long hash) 718 { 719 long b, i, n; 720 long bn; 721 long my_bitno; 722 long my_hmask; 723 long my_blkno; 724 int j = (sizeof (my_hmask)) * 8; 725 off64_t where; 726 727 for (my_hmask = 0; j-- > 0; my_hmask = (my_hmask<<1) + 1) { 728 my_blkno = hash & my_hmask; 729 my_bitno = my_blkno + my_hmask; 730 /* getbit inline */ 731 if (my_bitno > db->dbm_maxbno) break; 732 n = my_bitno % BYTESIZ; 733 bn = my_bitno / BYTESIZ; 734 i = bn % DBLKSIZ; 735 b = bn / DBLKSIZ; 736 if (b != db->dbm_dirbno) { 737 if (dbm_dirdirty(db)) 738 (void) dbm_flushdir(db); /* must flush */ 739 db->dbm_dirbno = b; 740 where = (((off64_t)b) * DBLKSIZ); 741 if ((lseek64(db->dbm_dirf, where, L_SET) != where) || 742 (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != 743 DBLKSIZ)) 744 (void) memset(db->dbm_dirbuf, 0, DBLKSIZ); 745 } 746 if ((db->dbm_dirbuf[i] & (1<<n)) == 0) break; 747 748 /* 749 * if (getbit(db) == 0) 750 * break; 751 */ 752 } 753 /* copy */ 754 db->dbm_blkno = my_blkno; 755 db->dbm_bitno = my_bitno; 756 db->dbm_hmask = my_hmask; 757 758 if (my_blkno != db->dbm_pagbno) { 759 if (dbm_dirty(db)) { /* must page out the page */ 760 where = (((off64_t)db->dbm_pagbno) * PBLKSIZ); 761 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 762 (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != 763 PBLKSIZ)) { 764 db->dbm_flags |= _DBM_IOERR; 765 } 766 dbm_clrdirty(db); 767 } 768 769 db->dbm_pagbno = my_blkno; 770 where = (((off64_t)my_blkno) * PBLKSIZ); 771 if ((lseek64(db->dbm_pagf, where, L_SET) != where) || 772 (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ)) 773 (void) memset(db->dbm_pagbuf, 0, PBLKSIZ); 774 #ifdef DEBUG 775 else if (chkblk(db->dbm_pagbuf) < 0) 776 db->dbm_flags |= _DBM_IOERR; 777 #endif 778 } 779 } 780 781 static int 782 getbit(DBM *db) 783 { 784 long bn; 785 long b, i, n; 786 off64_t where; 787 788 if (db->dbm_bitno > db->dbm_maxbno) 789 return (0); 790 n = db->dbm_bitno % BYTESIZ; 791 bn = db->dbm_bitno / BYTESIZ; 792 i = bn % DBLKSIZ; 793 b = bn / DBLKSIZ; 794 if (b != db->dbm_dirbno) { 795 if (dbm_dirdirty(db)) 796 (void) dbm_flushdir(db); /* must flush */ 797 db->dbm_dirbno = b; 798 where = (((off64_t)b) * DBLKSIZ); 799 if ((lseek64(db->dbm_dirf, where, L_SET) != where) || 800 (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ)) 801 (void) memset(db->dbm_dirbuf, 0, DBLKSIZ); 802 } 803 return (db->dbm_dirbuf[i] & (1<<n)); 804 } 805 806 static int 807 setbit(DBM *db) 808 { 809 long bn; 810 long i, n, b; 811 off64_t where; 812 813 if (db->dbm_bitno > db->dbm_maxbno) 814 db->dbm_maxbno = db->dbm_bitno; 815 n = db->dbm_bitno % BYTESIZ; 816 bn = db->dbm_bitno / BYTESIZ; 817 i = bn % DBLKSIZ; 818 b = bn / DBLKSIZ; 819 if (b != db->dbm_dirbno) { 820 if (dbm_dirdirty(db)) 821 (void) dbm_flushdir(db); 822 db->dbm_dirbno = b; 823 where = (((off64_t)b) * DBLKSIZ); 824 if ((lseek64(db->dbm_dirf, where, L_SET) != where) || 825 (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ)) 826 (void) memset(db->dbm_dirbuf, 0, DBLKSIZ); 827 } 828 db->dbm_dirbuf[i] |= 1<<n; 829 db->dbm_dirbno = b; 830 if (dbm_defwrite(db)) { 831 dbm_setdirdirty(db); 832 } else { 833 where = (((off64_t)b) * DBLKSIZ); 834 if ((lseek64(db->dbm_dirf, where, L_SET) != where) || 835 (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ)) { 836 return (-1); 837 } 838 } 839 return (0); 840 } 841 842 static datum 843 makdatum(char buf[PBLKSIZ], int n) 844 { 845 short *sp; 846 int t; 847 datum item; 848 849 sp = (short *)(uintptr_t)buf; 850 if ((unsigned)n >= sp[0]) { 851 item.dptr = NULL; 852 item.dsize = 0; 853 return (item); 854 } 855 t = PBLKSIZ; 856 if (n > 0) 857 t = sp[n]; 858 item.dptr = buf + sp[n + 1]; 859 item.dsize = t - sp[n + 1]; 860 return (item); 861 } 862 863 static int 864 cmpdatum(datum d1, datum d2) 865 { 866 long n; 867 char *p1, *p2; 868 869 n = d1.dsize; 870 if (n != d2.dsize) 871 return ((int)(n - d2.dsize)); 872 if (n == 0) 873 return (0); 874 p1 = d1.dptr; 875 p2 = d2.dptr; 876 do { 877 if (*p1 != *p2) 878 return (*p1 - *p2); 879 else { 880 p1++; 881 p2++; 882 } 883 } while (--n); 884 return (0); 885 } 886 887 static int 888 finddatum(char buf[PBLKSIZ], datum item) 889 { 890 short *sp; 891 int i, n, j; 892 893 sp = (short *)(uintptr_t)buf; 894 n = PBLKSIZ; 895 for (i = 0, j = sp[0]; i < j; i += 2, n = sp[i]) { 896 n -= sp[i + 1]; 897 if (n != item.dsize) 898 continue; 899 if (n == 0 || memcmp(&buf[sp[i+1]], item.dptr, n) == 0) 900 return (i); 901 } 902 return (-1); 903 } 904 905 static const int hitab[16] 906 /* 907 * ken's 908 * { 909 * 055, 043, 036, 054, 063, 014, 004, 005, 910 * 010, 064, 077, 000, 035, 027, 025, 071, 911 * }; 912 */ 913 = { 61, 57, 53, 49, 45, 41, 37, 33, 914 29, 25, 21, 17, 13, 9, 5, 1, 915 }; 916 917 /* could consider to make it 32-bit int table to minimize memory usage */ 918 static const long hltab[64] 919 = { 920 06100151277L, 06106161736L, 06452611562L, 05001724107L, 921 02614772546L, 04120731531L, 04665262210L, 07347467531L, 922 06735253126L, 06042345173L, 03072226605L, 01464164730L, 923 03247435524L, 07652510057L, 01546775256L, 05714532133L, 924 06173260402L, 07517101630L, 02431460343L, 01743245566L, 925 00261675137L, 02433103631L, 03421772437L, 04447707466L, 926 04435620103L, 03757017115L, 03641531772L, 06767633246L, 927 02673230344L, 00260612216L, 04133454451L, 00615531516L, 928 06137717526L, 02574116560L, 02304023373L, 07061702261L, 929 05153031405L, 05322056705L, 07401116734L, 06552375715L, 930 06165233473L, 05311063631L, 01212221723L, 01052267235L, 931 06000615237L, 01075222665L, 06330216006L, 04402355630L, 932 01451177262L, 02000133436L, 06025467062L, 07121076461L, 933 03123433522L, 01010635225L, 01716177066L, 05161746527L, 934 01736635071L, 06243505026L, 03637211610L, 01756474365L, 935 04723077174L, 03642763134L, 05750130273L, 03655541561L, 936 }; 937 938 static unsigned long 939 dcalchash(datum item) 940 { 941 long s; 942 int c, j; 943 char *cp; 944 unsigned long hashl; 945 long hashi; 946 947 hashl = 0; 948 hashi = 0; 949 for (cp = item.dptr, s = item.dsize; --s >= 0; ) { 950 c = *cp++; 951 for (j = 0; j < BYTESIZ; j += 4) { 952 hashi += hitab[c&017]; 953 hashl += hltab[hashi&63]; 954 c >>= 4; 955 } 956 } 957 return (hashl); 958 } 959 960 /* 961 * Delete pairs of items (n & n+1). 962 */ 963 static int 964 delitem(char buf[PBLKSIZ], int n) 965 { 966 short *sp, *sp1; 967 int i1, i2; 968 969 sp = (short *)(uintptr_t)buf; 970 i2 = sp[0]; 971 if ((unsigned)n >= i2 || (n & 1)) 972 return (0); 973 if (n == i2-2) { 974 sp[0] -= 2; 975 return (1); 976 } 977 i1 = PBLKSIZ; 978 if (n > 0) 979 i1 = sp[n]; 980 i1 -= sp[n+2]; 981 if (i1 > 0) { 982 i2 = sp[i2]; 983 (void) memmove(&buf[i2 + i1], &buf[i2], sp[n+2] - i2); 984 } 985 sp[0] -= 2; 986 for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) 987 sp[0] = sp[2] + i1; 988 return (1); 989 } 990 991 /* 992 * Add pairs of items (item & item1). 993 */ 994 static int 995 additem(char buf[PBLKSIZ], datum item, datum item1) 996 { 997 short *sp; 998 int i1, i2; 999 1000 sp = (short *)(uintptr_t)buf; 1001 i1 = PBLKSIZ; 1002 i2 = sp[0]; 1003 if (i2 > 0) 1004 i1 = sp[i2]; 1005 i1 -= item.dsize + item1.dsize; 1006 if (i1 <= (i2+3) * (int)sizeof (short)) 1007 return (0); 1008 sp[0] += 2; 1009 sp[++i2] = (short)(i1 + item1.dsize); 1010 (void) memmove(&buf[i1 + item1.dsize], item.dptr, item.dsize); 1011 sp[++i2] = i1; 1012 (void) memmove(&buf[i1], item1.dptr, item1.dsize); 1013 return (1); 1014 } 1015 1016 #ifdef DEBUG 1017 static int 1018 chkblk(char buf[PBLKSIZ]) 1019 { 1020 short *sp; 1021 int t, i; 1022 1023 sp = (short *)buf; 1024 t = PBLKSIZ; 1025 for (i = 0; i < sp[0]; i++) { 1026 if (sp[i + 1] > t) 1027 return (-1); 1028 t = sp[i + 1]; 1029 } 1030 if (t < (sp[0] + 1) * sizeof (short)) 1031 return (-1); 1032 return (0); 1033 } 1034 #endif 1035