1*15646Sralph #ifndef lint 2*15646Sralph static char sccsid[] = "@(#)ndbm.c 4.1 (Berkeley) 12/02/83"; 3*15646Sralph #endif 4*15646Sralph 5*15646Sralph #include <sys/types.h> 6*15646Sralph #include <sys/stat.h> 7*15646Sralph #include <sys/file.h> 8*15646Sralph #include <errno.h> 9*15646Sralph #include <ndbm.h> 10*15646Sralph 11*15646Sralph #define NULL (char *)0 12*15646Sralph #define BYTESIZ 8 13*15646Sralph 14*15646Sralph static datum firsthash(); 15*15646Sralph static dbm_access(); 16*15646Sralph static getbit(); 17*15646Sralph static setbit(); 18*15646Sralph static datum makdatum(); 19*15646Sralph static cmpdatum(); 20*15646Sralph static long hashinc(); 21*15646Sralph static long dcalchash(); 22*15646Sralph static delitem(); 23*15646Sralph static additem(); 24*15646Sralph static chkblk(); 25*15646Sralph extern int errno; 26*15646Sralph 27*15646Sralph DBM * 28*15646Sralph ndbmopen(file, flags, mode) 29*15646Sralph char *file; 30*15646Sralph int flags, mode; 31*15646Sralph { 32*15646Sralph struct stat statb; 33*15646Sralph register DBM *db; 34*15646Sralph 35*15646Sralph if ((db = (DBM *)malloc(sizeof *db)) == 0) { 36*15646Sralph errno = ENOMEM; 37*15646Sralph return ((DBM *)0); 38*15646Sralph } 39*15646Sralph if ((flags & 03) == O_WRONLY) 40*15646Sralph flags = (flags & ~03) | O_RDWR; 41*15646Sralph db->db_flags = 0; 42*15646Sralph strcpy(db->db_pagbuf, file); 43*15646Sralph strcat(db->db_pagbuf, ".pag"); 44*15646Sralph db->db_pagf = open(db->db_pagbuf, flags, mode); 45*15646Sralph if (db->db_pagf < 0) 46*15646Sralph goto bad; 47*15646Sralph strcpy(db->db_pagbuf, file); 48*15646Sralph strcat(db->db_pagbuf, ".dir"); 49*15646Sralph db->db_dirf = open(db->db_pagbuf, flags, mode); 50*15646Sralph if (db->db_dirf < 0) 51*15646Sralph goto bad1; 52*15646Sralph fstat(db->db_dirf, &statb); 53*15646Sralph db->db_maxbno = statb.st_size*BYTESIZ-1; 54*15646Sralph db->db_pagbno = db->db_dirbno = -1; 55*15646Sralph return (db); 56*15646Sralph bad1: 57*15646Sralph (void) close(db->db_pagf); 58*15646Sralph bad: 59*15646Sralph free((char *)db); 60*15646Sralph return ((DBM *)0); 61*15646Sralph } 62*15646Sralph 63*15646Sralph void 64*15646Sralph ndbmclose(db) 65*15646Sralph DBM *db; 66*15646Sralph { 67*15646Sralph 68*15646Sralph (void) close(db->db_dirf); 69*15646Sralph (void) close(db->db_pagf); 70*15646Sralph free((char *)db); 71*15646Sralph } 72*15646Sralph 73*15646Sralph long 74*15646Sralph dbmforder(db, key) 75*15646Sralph register DBM *db; 76*15646Sralph datum key; 77*15646Sralph { 78*15646Sralph long hash; 79*15646Sralph 80*15646Sralph hash = dcalchash(key); 81*15646Sralph for (db->db_hmask=0;; db->db_hmask=(db->db_hmask<<1)+1) { 82*15646Sralph db->db_blkno = hash & db->db_hmask; 83*15646Sralph db->db_bitno = db->db_blkno + db->db_hmask; 84*15646Sralph if (getbit(db) == 0) 85*15646Sralph break; 86*15646Sralph } 87*15646Sralph return (db->db_blkno); 88*15646Sralph } 89*15646Sralph 90*15646Sralph datum 91*15646Sralph dbmfetch(db, key) 92*15646Sralph register DBM *db; 93*15646Sralph datum key; 94*15646Sralph { 95*15646Sralph register i; 96*15646Sralph datum item; 97*15646Sralph 98*15646Sralph dbm_access(db, dcalchash(key)); 99*15646Sralph for (i=0;; i+=2) { 100*15646Sralph item = makdatum(db->db_pagbuf, i); 101*15646Sralph if (item.dptr == NULL) 102*15646Sralph return (item); 103*15646Sralph if (cmpdatum(key, item) == 0) { 104*15646Sralph item = makdatum(db->db_pagbuf, i+1); 105*15646Sralph if (item.dptr == NULL) 106*15646Sralph printf("items not in pairs\n"); 107*15646Sralph return (item); 108*15646Sralph } 109*15646Sralph } 110*15646Sralph } 111*15646Sralph 112*15646Sralph dbmdelete(db, key) 113*15646Sralph register DBM *db; 114*15646Sralph datum key; 115*15646Sralph { 116*15646Sralph register i; 117*15646Sralph datum item; 118*15646Sralph 119*15646Sralph if (dbrdonly(db)) { 120*15646Sralph errno = EPERM; 121*15646Sralph return (-1); 122*15646Sralph } 123*15646Sralph dbm_access(db, dcalchash(key)); 124*15646Sralph for (i=0;; i+=2) { 125*15646Sralph item = makdatum(db->db_pagbuf, i); 126*15646Sralph if (item.dptr == NULL) 127*15646Sralph return (-1); 128*15646Sralph if (cmpdatum(key, item) == 0) { 129*15646Sralph delitem(db->db_pagbuf, i); 130*15646Sralph delitem(db->db_pagbuf, i); 131*15646Sralph break; 132*15646Sralph } 133*15646Sralph } 134*15646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 135*15646Sralph (void) write(db->db_pagf, db->db_pagbuf, PBLKSIZ); 136*15646Sralph db->db_pagbno = db->db_blkno; 137*15646Sralph return (0); 138*15646Sralph } 139*15646Sralph 140*15646Sralph dbmstore(db, key, dat) 141*15646Sralph register DBM *db; 142*15646Sralph datum key, dat; 143*15646Sralph { 144*15646Sralph register i; 145*15646Sralph datum item; 146*15646Sralph char ovfbuf[PBLKSIZ]; 147*15646Sralph 148*15646Sralph if (dbrdonly(db)) { 149*15646Sralph errno = EPERM; 150*15646Sralph return (-1); 151*15646Sralph } 152*15646Sralph loop: 153*15646Sralph dbm_access(db, dcalchash(key)); 154*15646Sralph for (i=0;; i+=2) { 155*15646Sralph item = makdatum(db->db_pagbuf, i); 156*15646Sralph if (item.dptr == NULL) 157*15646Sralph break; 158*15646Sralph if (cmpdatum(key, item) == 0) { 159*15646Sralph return(0); 160*15646Sralph /* 161*15646Sralph delitem(db->db_pagbuf, i); 162*15646Sralph delitem(db->db_pagbuf, i); 163*15646Sralph break; 164*15646Sralph */ 165*15646Sralph } 166*15646Sralph } 167*15646Sralph i = additem(db->db_pagbuf, key); 168*15646Sralph if (i < 0) 169*15646Sralph goto split; 170*15646Sralph if (additem(db->db_pagbuf, dat) < 0) { 171*15646Sralph delitem(db->db_pagbuf, i); 172*15646Sralph goto split; 173*15646Sralph } 174*15646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 175*15646Sralph (void) write(db->db_pagf, db->db_pagbuf, PBLKSIZ); 176*15646Sralph db->db_pagbno = db->db_blkno; 177*15646Sralph return (0); 178*15646Sralph 179*15646Sralph split: 180*15646Sralph if (key.dsize+dat.dsize+2*sizeof(short) >= PBLKSIZ) { 181*15646Sralph errno = ENOSPC; 182*15646Sralph return (-1); 183*15646Sralph } 184*15646Sralph bzero(ovfbuf, PBLKSIZ); 185*15646Sralph for (i=0;;) { 186*15646Sralph item = makdatum(db->db_pagbuf, i); 187*15646Sralph if (item.dptr == NULL) 188*15646Sralph break; 189*15646Sralph if (dcalchash(item) & (db->db_hmask+1)) { 190*15646Sralph additem(ovfbuf, item); 191*15646Sralph delitem(db->db_pagbuf, i); 192*15646Sralph item = makdatum(db->db_pagbuf, i); 193*15646Sralph if (item.dptr == NULL) { 194*15646Sralph printf("ndbm: split not paired\n"); 195*15646Sralph break; 196*15646Sralph } 197*15646Sralph additem(ovfbuf, item); 198*15646Sralph delitem(db->db_pagbuf, i); 199*15646Sralph continue; 200*15646Sralph } 201*15646Sralph i += 2; 202*15646Sralph } 203*15646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 204*15646Sralph (void) write(db->db_pagf, db->db_pagbuf, PBLKSIZ); 205*15646Sralph db->db_pagbno = db->db_blkno; 206*15646Sralph (void) lseek(db->db_pagf, (db->db_blkno+db->db_hmask+1)*PBLKSIZ, L_SET); 207*15646Sralph (void) write(db->db_pagf, ovfbuf, PBLKSIZ); 208*15646Sralph setbit(db); 209*15646Sralph goto loop; 210*15646Sralph } 211*15646Sralph 212*15646Sralph datum 213*15646Sralph dbmfirstkey(db) 214*15646Sralph DBM *db; 215*15646Sralph { 216*15646Sralph 217*15646Sralph return (firsthash(db, 0L)); 218*15646Sralph } 219*15646Sralph 220*15646Sralph datum 221*15646Sralph dbmnextkey(db, key) 222*15646Sralph register DBM *db; 223*15646Sralph datum key; 224*15646Sralph { 225*15646Sralph register i; 226*15646Sralph datum item, bitem; 227*15646Sralph long hash; 228*15646Sralph int f; 229*15646Sralph 230*15646Sralph hash = dcalchash(key); 231*15646Sralph dbm_access(db, hash); 232*15646Sralph f = 1; 233*15646Sralph for (i=0;; i+=2) { 234*15646Sralph item = makdatum(db->db_pagbuf, i); 235*15646Sralph if (item.dptr == NULL) 236*15646Sralph break; 237*15646Sralph if (cmpdatum(key, item) <= 0) 238*15646Sralph continue; 239*15646Sralph if (f || cmpdatum(bitem, item) < 0) { 240*15646Sralph bitem = item; 241*15646Sralph f = 0; 242*15646Sralph } 243*15646Sralph } 244*15646Sralph if (f == 0) 245*15646Sralph return (bitem); 246*15646Sralph hash = hashinc(db, hash); 247*15646Sralph if (hash == 0) 248*15646Sralph return (item); 249*15646Sralph return (firsthash(db, hash)); 250*15646Sralph } 251*15646Sralph 252*15646Sralph static datum 253*15646Sralph firsthash(db, hash) 254*15646Sralph register DBM *db; 255*15646Sralph long hash; 256*15646Sralph { 257*15646Sralph register i; 258*15646Sralph datum item, bitem; 259*15646Sralph 260*15646Sralph loop: 261*15646Sralph dbm_access(db, hash); 262*15646Sralph bitem = makdatum(db->db_pagbuf, 0); 263*15646Sralph for (i=2;; i+=2) { 264*15646Sralph item = makdatum(db->db_pagbuf, i); 265*15646Sralph if (item.dptr == NULL) 266*15646Sralph break; 267*15646Sralph if (cmpdatum(bitem, item) < 0) 268*15646Sralph bitem = item; 269*15646Sralph } 270*15646Sralph if (bitem.dptr != NULL) 271*15646Sralph return (bitem); 272*15646Sralph hash = hashinc(db, hash); 273*15646Sralph if (hash == 0) 274*15646Sralph return (item); 275*15646Sralph goto loop; 276*15646Sralph } 277*15646Sralph 278*15646Sralph static 279*15646Sralph dbm_access(db, hash) 280*15646Sralph register DBM *db; 281*15646Sralph long hash; 282*15646Sralph { 283*15646Sralph 284*15646Sralph for (db->db_hmask=0;; db->db_hmask=(db->db_hmask<<1)+1) { 285*15646Sralph db->db_blkno = hash & db->db_hmask; 286*15646Sralph db->db_bitno = db->db_blkno + db->db_hmask; 287*15646Sralph if (getbit(db) == 0) 288*15646Sralph break; 289*15646Sralph } 290*15646Sralph if (db->db_blkno != db->db_pagbno) { 291*15646Sralph bzero(db->db_pagbuf, PBLKSIZ); 292*15646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 293*15646Sralph (void) read(db->db_pagf, db->db_pagbuf, PBLKSIZ); 294*15646Sralph chkblk(db->db_pagbuf); 295*15646Sralph db->db_pagbno = db->db_blkno; 296*15646Sralph } 297*15646Sralph } 298*15646Sralph 299*15646Sralph static 300*15646Sralph getbit(db) 301*15646Sralph register DBM *db; 302*15646Sralph { 303*15646Sralph long bn; 304*15646Sralph register b, i, n; 305*15646Sralph 306*15646Sralph 307*15646Sralph if (db->db_bitno > db->db_maxbno) 308*15646Sralph return (0); 309*15646Sralph n = db->db_bitno % BYTESIZ; 310*15646Sralph bn = db->db_bitno / BYTESIZ; 311*15646Sralph i = bn % DBLKSIZ; 312*15646Sralph b = bn / DBLKSIZ; 313*15646Sralph if (b != db->db_dirbno) { 314*15646Sralph bzero(db->db_dirbuf, DBLKSIZ); 315*15646Sralph (void) lseek(db->db_dirf, (long)b*DBLKSIZ, L_SET); 316*15646Sralph (void) read(db->db_dirf, db->db_dirbuf, DBLKSIZ); 317*15646Sralph db->db_dirbno = b; 318*15646Sralph } 319*15646Sralph if (db->db_dirbuf[i] & (1<<n)) 320*15646Sralph return (1); 321*15646Sralph return (0); 322*15646Sralph } 323*15646Sralph 324*15646Sralph static 325*15646Sralph setbit(db) 326*15646Sralph register DBM *db; 327*15646Sralph { 328*15646Sralph long bn; 329*15646Sralph register i, n, b; 330*15646Sralph 331*15646Sralph if (dbrdonly(db)) { 332*15646Sralph errno = EPERM; 333*15646Sralph return (-1); 334*15646Sralph } 335*15646Sralph if (db->db_bitno > db->db_maxbno) { 336*15646Sralph db->db_maxbno = db->db_bitno; 337*15646Sralph getbit(db); 338*15646Sralph } 339*15646Sralph n = db->db_bitno % BYTESIZ; 340*15646Sralph bn = db->db_bitno / BYTESIZ; 341*15646Sralph i = bn % DBLKSIZ; 342*15646Sralph b = bn / DBLKSIZ; 343*15646Sralph db->db_dirbuf[i] |= 1<<n; 344*15646Sralph (void) lseek(db->db_dirf, (long)b*DBLKSIZ, L_SET); 345*15646Sralph (void) write(db->db_dirf, db->db_dirbuf, DBLKSIZ); 346*15646Sralph db->db_dirbno = b; 347*15646Sralph } 348*15646Sralph 349*15646Sralph static datum 350*15646Sralph makdatum(buf, n) 351*15646Sralph char buf[PBLKSIZ]; 352*15646Sralph { 353*15646Sralph register short *sp; 354*15646Sralph register t; 355*15646Sralph datum item; 356*15646Sralph 357*15646Sralph sp = (short *)buf; 358*15646Sralph if (n < 0 || n >= sp[0]) 359*15646Sralph goto null; 360*15646Sralph t = PBLKSIZ; 361*15646Sralph if (n > 0) 362*15646Sralph t = sp[n+1-1]; 363*15646Sralph item.dptr = buf+sp[n+1]; 364*15646Sralph item.dsize = t - sp[n+1]; 365*15646Sralph return (item); 366*15646Sralph 367*15646Sralph null: 368*15646Sralph item.dptr = NULL; 369*15646Sralph item.dsize = 0; 370*15646Sralph return (item); 371*15646Sralph } 372*15646Sralph 373*15646Sralph static 374*15646Sralph cmpdatum(d1, d2) 375*15646Sralph datum d1, d2; 376*15646Sralph { 377*15646Sralph register n; 378*15646Sralph register char *p1, *p2; 379*15646Sralph 380*15646Sralph n = d1.dsize; 381*15646Sralph if (n != d2.dsize) 382*15646Sralph return (n - d2.dsize); 383*15646Sralph if (n == 0) 384*15646Sralph return (0); 385*15646Sralph p1 = d1.dptr; 386*15646Sralph p2 = d2.dptr; 387*15646Sralph do 388*15646Sralph if (*p1++ != *p2++) 389*15646Sralph return (*--p1 - *--p2); 390*15646Sralph while (--n); 391*15646Sralph return (0); 392*15646Sralph } 393*15646Sralph 394*15646Sralph static int hitab[16] 395*15646Sralph /* ken's 396*15646Sralph { 397*15646Sralph 055,043,036,054,063,014,004,005, 398*15646Sralph 010,064,077,000,035,027,025,071, 399*15646Sralph }; 400*15646Sralph */ 401*15646Sralph = { 61, 57, 53, 49, 45, 41, 37, 33, 402*15646Sralph 29, 25, 21, 17, 13, 9, 5, 1, 403*15646Sralph }; 404*15646Sralph static long hltab[64] 405*15646Sralph = { 406*15646Sralph 06100151277L,06106161736L,06452611562L,05001724107L, 407*15646Sralph 02614772546L,04120731531L,04665262210L,07347467531L, 408*15646Sralph 06735253126L,06042345173L,03072226605L,01464164730L, 409*15646Sralph 03247435524L,07652510057L,01546775256L,05714532133L, 410*15646Sralph 06173260402L,07517101630L,02431460343L,01743245566L, 411*15646Sralph 00261675137L,02433103631L,03421772437L,04447707466L, 412*15646Sralph 04435620103L,03757017115L,03641531772L,06767633246L, 413*15646Sralph 02673230344L,00260612216L,04133454451L,00615531516L, 414*15646Sralph 06137717526L,02574116560L,02304023373L,07061702261L, 415*15646Sralph 05153031405L,05322056705L,07401116734L,06552375715L, 416*15646Sralph 06165233473L,05311063631L,01212221723L,01052267235L, 417*15646Sralph 06000615237L,01075222665L,06330216006L,04402355630L, 418*15646Sralph 01451177262L,02000133436L,06025467062L,07121076461L, 419*15646Sralph 03123433522L,01010635225L,01716177066L,05161746527L, 420*15646Sralph 01736635071L,06243505026L,03637211610L,01756474365L, 421*15646Sralph 04723077174L,03642763134L,05750130273L,03655541561L, 422*15646Sralph }; 423*15646Sralph 424*15646Sralph static long 425*15646Sralph hashinc(db, hash) 426*15646Sralph register DBM *db; 427*15646Sralph long hash; 428*15646Sralph { 429*15646Sralph long bit; 430*15646Sralph 431*15646Sralph hash &= db->db_hmask; 432*15646Sralph bit = db->db_hmask+1; 433*15646Sralph for (;;) { 434*15646Sralph bit >>= 1; 435*15646Sralph if (bit == 0) 436*15646Sralph return (0L); 437*15646Sralph if ((hash&bit) == 0) 438*15646Sralph return (hash|bit); 439*15646Sralph hash &= ~bit; 440*15646Sralph } 441*15646Sralph } 442*15646Sralph 443*15646Sralph static long 444*15646Sralph dcalchash(item) 445*15646Sralph datum item; 446*15646Sralph { 447*15646Sralph register i, j, f; 448*15646Sralph long hashl; 449*15646Sralph int hashi; 450*15646Sralph 451*15646Sralph hashl = 0; 452*15646Sralph hashi = 0; 453*15646Sralph for (i=0; i<item.dsize; i++) { 454*15646Sralph f = item.dptr[i]; 455*15646Sralph for (j=0; j<BYTESIZ; j+=4) { 456*15646Sralph hashi += hitab[f&017]; 457*15646Sralph hashl += hltab[hashi&63]; 458*15646Sralph f >>= 4; 459*15646Sralph } 460*15646Sralph } 461*15646Sralph return (hashl); 462*15646Sralph } 463*15646Sralph 464*15646Sralph static 465*15646Sralph delitem(buf, n) 466*15646Sralph char buf[PBLKSIZ]; 467*15646Sralph { 468*15646Sralph register short *sp; 469*15646Sralph register i1, i2, i3; 470*15646Sralph 471*15646Sralph sp = (short *)buf; 472*15646Sralph if (n < 0 || n >= sp[0]) 473*15646Sralph goto bad; 474*15646Sralph i1 = sp[n+1]; 475*15646Sralph i2 = PBLKSIZ; 476*15646Sralph if (n > 0) 477*15646Sralph i2 = sp[n+1-1]; 478*15646Sralph i3 = sp[sp[0]+1-1]; 479*15646Sralph if (i2 > i1) 480*15646Sralph while (i1 > i3) { 481*15646Sralph i1--; 482*15646Sralph i2--; 483*15646Sralph buf[i2] = buf[i1]; 484*15646Sralph buf[i1] = 0; 485*15646Sralph } 486*15646Sralph i2 -= i1; 487*15646Sralph for (i1=n+1; i1<sp[0]; i1++) 488*15646Sralph sp[i1+1-1] = sp[i1+1] + i2; 489*15646Sralph sp[0]--; 490*15646Sralph sp[sp[0]+1] = 0; 491*15646Sralph return; 492*15646Sralph 493*15646Sralph bad: 494*15646Sralph printf("ndbm: bad delitem\n"); 495*15646Sralph abort(); 496*15646Sralph } 497*15646Sralph 498*15646Sralph static 499*15646Sralph additem(buf, item) 500*15646Sralph char buf[PBLKSIZ]; 501*15646Sralph datum item; 502*15646Sralph { 503*15646Sralph register short *sp; 504*15646Sralph register i1, i2; 505*15646Sralph 506*15646Sralph sp = (short *)buf; 507*15646Sralph i1 = PBLKSIZ; 508*15646Sralph if (sp[0] > 0) 509*15646Sralph i1 = sp[sp[0]+1-1]; 510*15646Sralph i1 -= item.dsize; 511*15646Sralph i2 = (sp[0]+2) * sizeof(short); 512*15646Sralph if (i1 <= i2) 513*15646Sralph return (-1); 514*15646Sralph sp[sp[0]+1] = i1; 515*15646Sralph for (i2=0; i2<item.dsize; i2++) { 516*15646Sralph buf[i1] = item.dptr[i2]; 517*15646Sralph i1++; 518*15646Sralph } 519*15646Sralph sp[0]++; 520*15646Sralph return (sp[0]-1); 521*15646Sralph } 522*15646Sralph 523*15646Sralph static 524*15646Sralph chkblk(buf) 525*15646Sralph char buf[PBLKSIZ]; 526*15646Sralph { 527*15646Sralph register short *sp; 528*15646Sralph register t, i; 529*15646Sralph 530*15646Sralph sp = (short *)buf; 531*15646Sralph t = PBLKSIZ; 532*15646Sralph for (i=0; i<sp[0]; i++) { 533*15646Sralph if (sp[i+1] > t) 534*15646Sralph goto bad; 535*15646Sralph t = sp[i+1]; 536*15646Sralph } 537*15646Sralph if (t < (sp[0]+1)*sizeof(short)) 538*15646Sralph goto bad; 539*15646Sralph return; 540*15646Sralph 541*15646Sralph bad: 542*15646Sralph printf("ndbm: bad block\n"); 543*15646Sralph abort(); 544*15646Sralph bzero(buf, PBLKSIZ); 545*15646Sralph } 546