115646Sralph #ifndef lint 2*17164Sralph static char sccsid[] = "@(#)ndbm.c 4.4 (Berkeley) 09/05/84"; 315646Sralph #endif 415646Sralph 515646Sralph #include <sys/types.h> 615646Sralph #include <sys/stat.h> 715646Sralph #include <sys/file.h> 817023Sralph #include <stdio.h> 915646Sralph #include <errno.h> 1015646Sralph #include <ndbm.h> 1115646Sralph 1215646Sralph #define BYTESIZ 8 1315646Sralph 1415646Sralph static datum makdatum(); 1515646Sralph static long hashinc(); 1615646Sralph static long dcalchash(); 1715646Sralph extern int errno; 1815646Sralph 1915646Sralph DBM * 2017023Sralph dbm_open(file, flags, mode) 2115646Sralph char *file; 2215646Sralph int flags, mode; 2315646Sralph { 2415646Sralph struct stat statb; 2515646Sralph register DBM *db; 2615646Sralph 2715646Sralph if ((db = (DBM *)malloc(sizeof *db)) == 0) { 2815646Sralph errno = ENOMEM; 2915646Sralph return ((DBM *)0); 3015646Sralph } 3117023Sralph db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; 3215646Sralph if ((flags & 03) == O_WRONLY) 3315646Sralph flags = (flags & ~03) | O_RDWR; 3417023Sralph strcpy(db->dbm_pagbuf, file); 3517023Sralph strcat(db->dbm_pagbuf, ".pag"); 3617023Sralph db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); 3717023Sralph if (db->dbm_pagf < 0) 3815646Sralph goto bad; 3917023Sralph strcpy(db->dbm_pagbuf, file); 4017023Sralph strcat(db->dbm_pagbuf, ".dir"); 4117023Sralph db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); 4217023Sralph if (db->dbm_dirf < 0) 4315646Sralph goto bad1; 4417023Sralph fstat(db->dbm_dirf, &statb); 4517023Sralph db->dbm_maxbno = statb.st_size*BYTESIZ-1; 4617023Sralph db->dbm_pagbno = db->dbm_dirbno = -1; 4715646Sralph return (db); 4815646Sralph bad1: 4917023Sralph (void) close(db->dbm_pagf); 5015646Sralph bad: 5115646Sralph free((char *)db); 5215646Sralph return ((DBM *)0); 5315646Sralph } 5415646Sralph 5515646Sralph void 5617023Sralph dbm_close(db) 5715646Sralph DBM *db; 5815646Sralph { 5915646Sralph 6017023Sralph (void) close(db->dbm_dirf); 6117023Sralph (void) close(db->dbm_pagf); 6215646Sralph free((char *)db); 6315646Sralph } 6415646Sralph 6515646Sralph long 6617023Sralph dbm_forder(db, key) 6715646Sralph register DBM *db; 6815646Sralph datum key; 6915646Sralph { 7015646Sralph long hash; 7115646Sralph 7215646Sralph hash = dcalchash(key); 7317023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 7417023Sralph db->dbm_blkno = hash & db->dbm_hmask; 7517023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 7615646Sralph if (getbit(db) == 0) 7715646Sralph break; 7815646Sralph } 7917023Sralph return (db->dbm_blkno); 8015646Sralph } 8115646Sralph 8215646Sralph datum 8317023Sralph dbm_fetch(db, key) 8415646Sralph register DBM *db; 8515646Sralph datum key; 8615646Sralph { 8715646Sralph register i; 8815646Sralph datum item; 8915646Sralph 9017023Sralph if (dbm_error(db)) 9117023Sralph goto err; 9215646Sralph dbm_access(db, dcalchash(key)); 93*17164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 94*17164Sralph item = makdatum(db->dbm_pagbuf, i+1); 95*17164Sralph if (item.dptr != NULL) 9615646Sralph return (item); 9715646Sralph } 9817023Sralph err: 9917023Sralph item.dptr = NULL; 10017023Sralph item.dsize = 0; 10117023Sralph return (item); 10215646Sralph } 10315646Sralph 10417023Sralph dbm_delete(db, key) 10515646Sralph register DBM *db; 10615646Sralph datum key; 10715646Sralph { 10815646Sralph register i; 10915646Sralph datum item; 11015646Sralph 11117023Sralph if (dbm_error(db)) 11217023Sralph return (-1); 11317023Sralph if (dbm_rdonly(db)) { 11415646Sralph errno = EPERM; 11515646Sralph return (-1); 11615646Sralph } 11715646Sralph dbm_access(db, dcalchash(key)); 118*17164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) < 0) 11917023Sralph return (-1); 120*17164Sralph if (!delitem(db->dbm_pagbuf, i)) 121*17164Sralph goto err; 12217023Sralph db->dbm_pagbno = db->dbm_blkno; 12317023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 12417023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 125*17164Sralph err: 12617023Sralph db->dbm_flags |= _DBM_IOERR; 12717023Sralph return (-1); 12817023Sralph } 12915646Sralph return (0); 13015646Sralph } 13115646Sralph 13217023Sralph dbm_store(db, key, dat, replace) 13315646Sralph register DBM *db; 13415646Sralph datum key, dat; 13515749Sralph int replace; 13615646Sralph { 13715646Sralph register i; 138*17164Sralph datum item, item1; 13915646Sralph char ovfbuf[PBLKSIZ]; 14015646Sralph 14117023Sralph if (dbm_error(db)) 14217023Sralph return (-1); 14317023Sralph if (dbm_rdonly(db)) { 14415646Sralph errno = EPERM; 14515646Sralph return (-1); 14615646Sralph } 14715646Sralph loop: 14815646Sralph dbm_access(db, dcalchash(key)); 149*17164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 150*17164Sralph if (!replace) 151*17164Sralph return (1); 152*17164Sralph if (!delitem(db->dbm_pagbuf, i)) { 153*17164Sralph db->dbm_flags |= _DBM_IOERR; 154*17164Sralph return (-1); 15515646Sralph } 15615646Sralph } 157*17164Sralph if (!additem(db->dbm_pagbuf, key, dat)) 15815646Sralph goto split; 15917023Sralph db->dbm_pagbno = db->dbm_blkno; 16017023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 16117023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 16217023Sralph db->dbm_flags |= _DBM_IOERR; 16317023Sralph return (-1); 16417023Sralph } 16515646Sralph return (0); 16615646Sralph 16715646Sralph split: 168*17164Sralph if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { 16917023Sralph db->dbm_flags |= _DBM_IOERR; 17015646Sralph errno = ENOSPC; 17115646Sralph return (-1); 17215646Sralph } 17315646Sralph bzero(ovfbuf, PBLKSIZ); 17415646Sralph for (i=0;;) { 17517023Sralph item = makdatum(db->dbm_pagbuf, i); 17615646Sralph if (item.dptr == NULL) 17715646Sralph break; 17817023Sralph if (dcalchash(item) & (db->dbm_hmask+1)) { 179*17164Sralph item1 = makdatum(db->dbm_pagbuf, i+1); 180*17164Sralph if (item1.dptr == NULL) { 18117023Sralph fprintf(stderr, "ndbm: split not paired\n"); 18217023Sralph db->dbm_flags |= _DBM_IOERR; 18315646Sralph break; 18415646Sralph } 185*17164Sralph if (!additem(ovfbuf, item, item1) || 18617023Sralph !delitem(db->dbm_pagbuf, i)) { 18717023Sralph db->dbm_flags |= _DBM_IOERR; 18817023Sralph return (-1); 18917023Sralph } 19015646Sralph continue; 19115646Sralph } 19215646Sralph i += 2; 19315646Sralph } 19417023Sralph db->dbm_pagbno = db->dbm_blkno; 19517023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 19617023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 19717023Sralph db->dbm_flags |= _DBM_IOERR; 19817023Sralph return (-1); 19917023Sralph } 20017023Sralph (void) lseek(db->dbm_pagf, (db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ, L_SET); 20117023Sralph if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { 20217023Sralph db->dbm_flags |= _DBM_IOERR; 20317023Sralph return (-1); 20417023Sralph } 20515646Sralph setbit(db); 20615646Sralph goto loop; 20715646Sralph } 20815646Sralph 20915646Sralph datum 21017023Sralph dbm_firstkey(db) 21115646Sralph DBM *db; 21215646Sralph { 21315646Sralph 214*17164Sralph db->dbm_blkptr = 0L; 215*17164Sralph db->dbm_keyptr = 0; 216*17164Sralph return (dbm_nextkey(db)); 21715646Sralph } 21815646Sralph 21915646Sralph datum 220*17164Sralph dbm_nextkey(db) 22115646Sralph register DBM *db; 22215646Sralph { 223*17164Sralph struct stat statb; 224*17164Sralph datum item; 22515646Sralph 226*17164Sralph if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) 22717023Sralph goto err; 228*17164Sralph statb.st_size /= PBLKSIZ; 229*17164Sralph for (;;) { 230*17164Sralph if (db->dbm_blkptr != db->dbm_pagbno) { 231*17164Sralph db->dbm_pagbno = db->dbm_blkptr; 232*17164Sralph (void) lseek(db->dbm_pagf, db->dbm_blkptr*PBLKSIZ, L_SET); 233*17164Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 234*17164Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 235*17164Sralph #ifdef DEBUG 236*17164Sralph else if (chkblk(db->dbm_pagbuf) < 0) 237*17164Sralph db->dbm_flags |= _DBM_IOERR; 238*17164Sralph #endif 239*17164Sralph } 240*17164Sralph if (((short *)db->dbm_pagbuf)[0] != 0) { 241*17164Sralph item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); 242*17164Sralph if (item.dptr != NULL) { 243*17164Sralph db->dbm_keyptr += 2; 244*17164Sralph return (item); 245*17164Sralph } 246*17164Sralph db->dbm_keyptr = 0; 247*17164Sralph } 248*17164Sralph if (++db->dbm_blkptr >= statb.st_size) 24915646Sralph break; 25015646Sralph } 25117023Sralph err: 25217023Sralph item.dptr = NULL; 25317023Sralph item.dsize = 0; 25417023Sralph return (item); 25515646Sralph } 25615646Sralph 25715646Sralph static 25815646Sralph dbm_access(db, hash) 25915646Sralph register DBM *db; 26015646Sralph long hash; 26115646Sralph { 262*17164Sralph 26317023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 26417023Sralph db->dbm_blkno = hash & db->dbm_hmask; 26517023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 26615646Sralph if (getbit(db) == 0) 26715646Sralph break; 26815646Sralph } 26917023Sralph if (db->dbm_blkno != db->dbm_pagbno) { 27017023Sralph db->dbm_pagbno = db->dbm_blkno; 27117023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 27217023Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 27317023Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 274*17164Sralph #ifdef DEBUG 27517023Sralph else if (chkblk(db->dbm_pagbuf) < 0) 27617023Sralph db->dbm_flags |= _DBM_IOERR; 277*17164Sralph #endif 27815646Sralph } 27915646Sralph } 28015646Sralph 28115646Sralph static 28215646Sralph getbit(db) 28315646Sralph register DBM *db; 28415646Sralph { 28515646Sralph long bn; 28615646Sralph register b, i, n; 28715646Sralph 28815646Sralph 28917023Sralph if (db->dbm_bitno > db->dbm_maxbno) 29015646Sralph return (0); 29117023Sralph n = db->dbm_bitno % BYTESIZ; 29217023Sralph bn = db->dbm_bitno / BYTESIZ; 29315646Sralph i = bn % DBLKSIZ; 29415646Sralph b = bn / DBLKSIZ; 29517023Sralph if (b != db->dbm_dirbno) { 29617023Sralph db->dbm_dirbno = b; 29717023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 29817023Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 29917023Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 30015646Sralph } 301*17164Sralph return (db->dbm_dirbuf[i] & (1<<n)); 30215646Sralph } 30315646Sralph 30415646Sralph static 30515646Sralph setbit(db) 30615646Sralph register DBM *db; 30715646Sralph { 30815646Sralph long bn; 30915646Sralph register i, n, b; 31015646Sralph 311*17164Sralph if (db->dbm_bitno > db->dbm_maxbno) 31217023Sralph db->dbm_maxbno = db->dbm_bitno; 31317023Sralph n = db->dbm_bitno % BYTESIZ; 31417023Sralph bn = db->dbm_bitno / BYTESIZ; 31515646Sralph i = bn % DBLKSIZ; 31615646Sralph b = bn / DBLKSIZ; 317*17164Sralph if (b != db->dbm_dirbno) { 318*17164Sralph db->dbm_dirbno = b; 319*17164Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 320*17164Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 321*17164Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 322*17164Sralph } 32317023Sralph db->dbm_dirbuf[i] |= 1<<n; 32417023Sralph db->dbm_dirbno = b; 32517023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 326*17164Sralph if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 32717023Sralph db->dbm_flags |= _DBM_IOERR; 32815646Sralph } 32915646Sralph 33015646Sralph static datum 33115646Sralph makdatum(buf, n) 33215646Sralph char buf[PBLKSIZ]; 33315646Sralph { 33415646Sralph register short *sp; 33515646Sralph register t; 33615646Sralph datum item; 33715646Sralph 33815646Sralph sp = (short *)buf; 339*17164Sralph if ((unsigned)n >= sp[0]) { 34017023Sralph item.dptr = NULL; 34117023Sralph item.dsize = 0; 34217023Sralph return (item); 34317023Sralph } 34415646Sralph t = PBLKSIZ; 34515646Sralph if (n > 0) 34617023Sralph t = sp[n]; 34715646Sralph item.dptr = buf+sp[n+1]; 34815646Sralph item.dsize = t - sp[n+1]; 34915646Sralph return (item); 35015646Sralph } 35115646Sralph 35215646Sralph static 353*17164Sralph finddatum(buf, item) 354*17164Sralph char buf[PBLKSIZ]; 355*17164Sralph datum item; 35615646Sralph { 357*17164Sralph register short *sp; 358*17164Sralph register int i, n, j; 35915646Sralph 360*17164Sralph sp = (short *)buf; 361*17164Sralph n = PBLKSIZ; 362*17164Sralph for (i=0, j=sp[0]; i<j; i+=2, n = sp[i]) { 363*17164Sralph n -= sp[i+1]; 364*17164Sralph if (n != item.dsize) 365*17164Sralph continue; 366*17164Sralph if (n == 0 || bcmp(&buf[sp[i+1]], item.dptr, n) == 0) 367*17164Sralph return (i); 368*17164Sralph } 369*17164Sralph return (-1); 37015646Sralph } 37115646Sralph 37215646Sralph static int hitab[16] 37315646Sralph /* ken's 37415646Sralph { 37515646Sralph 055,043,036,054,063,014,004,005, 37615646Sralph 010,064,077,000,035,027,025,071, 37715646Sralph }; 37815646Sralph */ 37915646Sralph = { 61, 57, 53, 49, 45, 41, 37, 33, 38015646Sralph 29, 25, 21, 17, 13, 9, 5, 1, 38115646Sralph }; 38215646Sralph static long hltab[64] 38315646Sralph = { 38415646Sralph 06100151277L,06106161736L,06452611562L,05001724107L, 38515646Sralph 02614772546L,04120731531L,04665262210L,07347467531L, 38615646Sralph 06735253126L,06042345173L,03072226605L,01464164730L, 38715646Sralph 03247435524L,07652510057L,01546775256L,05714532133L, 38815646Sralph 06173260402L,07517101630L,02431460343L,01743245566L, 38915646Sralph 00261675137L,02433103631L,03421772437L,04447707466L, 39015646Sralph 04435620103L,03757017115L,03641531772L,06767633246L, 39115646Sralph 02673230344L,00260612216L,04133454451L,00615531516L, 39215646Sralph 06137717526L,02574116560L,02304023373L,07061702261L, 39315646Sralph 05153031405L,05322056705L,07401116734L,06552375715L, 39415646Sralph 06165233473L,05311063631L,01212221723L,01052267235L, 39515646Sralph 06000615237L,01075222665L,06330216006L,04402355630L, 39615646Sralph 01451177262L,02000133436L,06025467062L,07121076461L, 39715646Sralph 03123433522L,01010635225L,01716177066L,05161746527L, 39815646Sralph 01736635071L,06243505026L,03637211610L,01756474365L, 39915646Sralph 04723077174L,03642763134L,05750130273L,03655541561L, 40015646Sralph }; 40115646Sralph 40215646Sralph static long 40315646Sralph hashinc(db, hash) 40415646Sralph register DBM *db; 40515646Sralph long hash; 40615646Sralph { 40715646Sralph long bit; 40815646Sralph 40917023Sralph hash &= db->dbm_hmask; 41017023Sralph bit = db->dbm_hmask+1; 41115646Sralph for (;;) { 41215646Sralph bit >>= 1; 41315646Sralph if (bit == 0) 41415646Sralph return (0L); 41517023Sralph if ((hash & bit) == 0) 41617023Sralph return (hash | bit); 41715646Sralph hash &= ~bit; 41815646Sralph } 41915646Sralph } 42015646Sralph 42115646Sralph static long 42215646Sralph dcalchash(item) 42315646Sralph datum item; 42415646Sralph { 42517023Sralph register int s, c, j; 42617023Sralph register char *cp; 42717023Sralph register long hashl; 42817023Sralph register int hashi; 42915646Sralph 43015646Sralph hashl = 0; 43115646Sralph hashi = 0; 43217023Sralph for (cp = item.dptr, s=item.dsize; --s >= 0; ) { 43317023Sralph c = *cp++; 43415646Sralph for (j=0; j<BYTESIZ; j+=4) { 43517023Sralph hashi += hitab[c&017]; 43615646Sralph hashl += hltab[hashi&63]; 43717023Sralph c >>= 4; 43815646Sralph } 43915646Sralph } 44015646Sralph return (hashl); 44115646Sralph } 44215646Sralph 443*17164Sralph /* 444*17164Sralph * Delete pairs of items (n & n+1). 445*17164Sralph */ 44615646Sralph static 44715646Sralph delitem(buf, n) 44815646Sralph char buf[PBLKSIZ]; 44915646Sralph { 45017023Sralph register short *sp, *sp1; 45117023Sralph register i1, i2; 45215646Sralph 45315646Sralph sp = (short *)buf; 45417023Sralph i2 = sp[0]; 455*17164Sralph if ((unsigned)n >= i2 || (n & 1)) 45617023Sralph return (0); 457*17164Sralph if (n == i2-2) { 458*17164Sralph sp[0] -= 2; 45917023Sralph return (1); 46017023Sralph } 46117023Sralph i1 = PBLKSIZ; 46215646Sralph if (n > 0) 46317023Sralph i1 = sp[n]; 464*17164Sralph i1 -= sp[n+2]; 46517023Sralph if (i1 > 0) { 46617023Sralph i2 = sp[i2]; 467*17164Sralph bcopy(&buf[i2], &buf[i2 + i1], sp[n+2] - i2); 46815646Sralph } 469*17164Sralph sp[0] -= 2; 470*17164Sralph for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) 471*17164Sralph sp[0] = sp[2] + i1; 47217023Sralph return (1); 47315646Sralph } 47415646Sralph 475*17164Sralph /* 476*17164Sralph * Add pairs of items (item & item1). 477*17164Sralph */ 47815646Sralph static 479*17164Sralph additem(buf, item, item1) 48015646Sralph char buf[PBLKSIZ]; 481*17164Sralph datum item, item1; 48215646Sralph { 48315646Sralph register short *sp; 48415646Sralph register i1, i2; 48515646Sralph 48615646Sralph sp = (short *)buf; 48715646Sralph i1 = PBLKSIZ; 48817023Sralph i2 = sp[0]; 48917023Sralph if (i2 > 0) 49017023Sralph i1 = sp[i2]; 491*17164Sralph i1 -= item.dsize + item1.dsize; 492*17164Sralph if (i1 <= (i2+3) * sizeof(short)) 49317023Sralph return (0); 494*17164Sralph sp[0] += 2; 495*17164Sralph sp[++i2] = i1 + item1.dsize; 496*17164Sralph bcopy(item.dptr, &buf[i1 + item1.dsize], item.dsize); 497*17164Sralph sp[++i2] = i1; 498*17164Sralph bcopy(item1.dptr, &buf[i1], item1.dsize); 49917023Sralph return (1); 50015646Sralph } 50115646Sralph 502*17164Sralph #ifdef DEBUG 50315646Sralph static 50415646Sralph chkblk(buf) 50515646Sralph char buf[PBLKSIZ]; 50615646Sralph { 50715646Sralph register short *sp; 50815646Sralph register t, i; 50915646Sralph 51015646Sralph sp = (short *)buf; 51115646Sralph t = PBLKSIZ; 51215646Sralph for (i=0; i<sp[0]; i++) { 51315646Sralph if (sp[i+1] > t) 51417023Sralph return (-1); 51515646Sralph t = sp[i+1]; 51615646Sralph } 51715646Sralph if (t < (sp[0]+1)*sizeof(short)) 51817023Sralph return (-1); 51917023Sralph return (0); 52015646Sralph } 521*17164Sralph #endif 522