115646Sralph #ifndef lint 2*15749Sralph static char sccsid[] = "@(#)ndbm.c 4.2 (Berkeley) 12/20/83"; 315646Sralph #endif 415646Sralph 515646Sralph #include <sys/types.h> 615646Sralph #include <sys/stat.h> 715646Sralph #include <sys/file.h> 815646Sralph #include <errno.h> 915646Sralph #include <ndbm.h> 1015646Sralph 1115646Sralph #define NULL (char *)0 1215646Sralph #define BYTESIZ 8 1315646Sralph 1415646Sralph static datum firsthash(); 1515646Sralph static dbm_access(); 1615646Sralph static getbit(); 1715646Sralph static setbit(); 1815646Sralph static datum makdatum(); 1915646Sralph static cmpdatum(); 2015646Sralph static long hashinc(); 2115646Sralph static long dcalchash(); 2215646Sralph static delitem(); 2315646Sralph static additem(); 2415646Sralph static chkblk(); 2515646Sralph extern int errno; 2615646Sralph 2715646Sralph DBM * 2815646Sralph ndbmopen(file, flags, mode) 2915646Sralph char *file; 3015646Sralph int flags, mode; 3115646Sralph { 3215646Sralph struct stat statb; 3315646Sralph register DBM *db; 3415646Sralph 3515646Sralph if ((db = (DBM *)malloc(sizeof *db)) == 0) { 3615646Sralph errno = ENOMEM; 3715646Sralph return ((DBM *)0); 3815646Sralph } 3915646Sralph if ((flags & 03) == O_WRONLY) 4015646Sralph flags = (flags & ~03) | O_RDWR; 4115646Sralph db->db_flags = 0; 4215646Sralph strcpy(db->db_pagbuf, file); 4315646Sralph strcat(db->db_pagbuf, ".pag"); 4415646Sralph db->db_pagf = open(db->db_pagbuf, flags, mode); 4515646Sralph if (db->db_pagf < 0) 4615646Sralph goto bad; 4715646Sralph strcpy(db->db_pagbuf, file); 4815646Sralph strcat(db->db_pagbuf, ".dir"); 4915646Sralph db->db_dirf = open(db->db_pagbuf, flags, mode); 5015646Sralph if (db->db_dirf < 0) 5115646Sralph goto bad1; 5215646Sralph fstat(db->db_dirf, &statb); 5315646Sralph db->db_maxbno = statb.st_size*BYTESIZ-1; 5415646Sralph db->db_pagbno = db->db_dirbno = -1; 5515646Sralph return (db); 5615646Sralph bad1: 5715646Sralph (void) close(db->db_pagf); 5815646Sralph bad: 5915646Sralph free((char *)db); 6015646Sralph return ((DBM *)0); 6115646Sralph } 6215646Sralph 6315646Sralph void 6415646Sralph ndbmclose(db) 6515646Sralph DBM *db; 6615646Sralph { 6715646Sralph 6815646Sralph (void) close(db->db_dirf); 6915646Sralph (void) close(db->db_pagf); 7015646Sralph free((char *)db); 7115646Sralph } 7215646Sralph 7315646Sralph long 7415646Sralph dbmforder(db, key) 7515646Sralph register DBM *db; 7615646Sralph datum key; 7715646Sralph { 7815646Sralph long hash; 7915646Sralph 8015646Sralph hash = dcalchash(key); 8115646Sralph for (db->db_hmask=0;; db->db_hmask=(db->db_hmask<<1)+1) { 8215646Sralph db->db_blkno = hash & db->db_hmask; 8315646Sralph db->db_bitno = db->db_blkno + db->db_hmask; 8415646Sralph if (getbit(db) == 0) 8515646Sralph break; 8615646Sralph } 8715646Sralph return (db->db_blkno); 8815646Sralph } 8915646Sralph 9015646Sralph datum 9115646Sralph dbmfetch(db, key) 9215646Sralph register DBM *db; 9315646Sralph datum key; 9415646Sralph { 9515646Sralph register i; 9615646Sralph datum item; 9715646Sralph 9815646Sralph dbm_access(db, dcalchash(key)); 9915646Sralph for (i=0;; i+=2) { 10015646Sralph item = makdatum(db->db_pagbuf, i); 10115646Sralph if (item.dptr == NULL) 10215646Sralph return (item); 10315646Sralph if (cmpdatum(key, item) == 0) { 10415646Sralph item = makdatum(db->db_pagbuf, i+1); 10515646Sralph if (item.dptr == NULL) 10615646Sralph printf("items not in pairs\n"); 10715646Sralph return (item); 10815646Sralph } 10915646Sralph } 11015646Sralph } 11115646Sralph 11215646Sralph dbmdelete(db, key) 11315646Sralph register DBM *db; 11415646Sralph datum key; 11515646Sralph { 11615646Sralph register i; 11715646Sralph datum item; 11815646Sralph 11915646Sralph if (dbrdonly(db)) { 12015646Sralph errno = EPERM; 12115646Sralph return (-1); 12215646Sralph } 12315646Sralph dbm_access(db, dcalchash(key)); 12415646Sralph for (i=0;; i+=2) { 12515646Sralph item = makdatum(db->db_pagbuf, i); 12615646Sralph if (item.dptr == NULL) 12715646Sralph return (-1); 12815646Sralph if (cmpdatum(key, item) == 0) { 12915646Sralph delitem(db->db_pagbuf, i); 13015646Sralph delitem(db->db_pagbuf, i); 13115646Sralph break; 13215646Sralph } 13315646Sralph } 13415646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 13515646Sralph (void) write(db->db_pagf, db->db_pagbuf, PBLKSIZ); 13615646Sralph db->db_pagbno = db->db_blkno; 13715646Sralph return (0); 13815646Sralph } 13915646Sralph 140*15749Sralph dbmstore(db, key, dat, replace) 14115646Sralph register DBM *db; 14215646Sralph datum key, dat; 143*15749Sralph int replace; 14415646Sralph { 14515646Sralph register i; 14615646Sralph datum item; 14715646Sralph char ovfbuf[PBLKSIZ]; 14815646Sralph 14915646Sralph if (dbrdonly(db)) { 15015646Sralph errno = EPERM; 15115646Sralph return (-1); 15215646Sralph } 15315646Sralph loop: 15415646Sralph dbm_access(db, dcalchash(key)); 15515646Sralph for (i=0;; i+=2) { 15615646Sralph item = makdatum(db->db_pagbuf, i); 15715646Sralph if (item.dptr == NULL) 15815646Sralph break; 15915646Sralph if (cmpdatum(key, item) == 0) { 160*15749Sralph if (!replace) 161*15749Sralph return (1); 16215646Sralph delitem(db->db_pagbuf, i); 16315646Sralph delitem(db->db_pagbuf, i); 16415646Sralph break; 16515646Sralph } 16615646Sralph } 16715646Sralph i = additem(db->db_pagbuf, key); 16815646Sralph if (i < 0) 16915646Sralph goto split; 17015646Sralph if (additem(db->db_pagbuf, dat) < 0) { 17115646Sralph delitem(db->db_pagbuf, i); 17215646Sralph goto split; 17315646Sralph } 17415646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 17515646Sralph (void) write(db->db_pagf, db->db_pagbuf, PBLKSIZ); 17615646Sralph db->db_pagbno = db->db_blkno; 17715646Sralph return (0); 17815646Sralph 17915646Sralph split: 18015646Sralph if (key.dsize+dat.dsize+2*sizeof(short) >= PBLKSIZ) { 18115646Sralph errno = ENOSPC; 18215646Sralph return (-1); 18315646Sralph } 18415646Sralph bzero(ovfbuf, PBLKSIZ); 18515646Sralph for (i=0;;) { 18615646Sralph item = makdatum(db->db_pagbuf, i); 18715646Sralph if (item.dptr == NULL) 18815646Sralph break; 18915646Sralph if (dcalchash(item) & (db->db_hmask+1)) { 19015646Sralph additem(ovfbuf, item); 19115646Sralph delitem(db->db_pagbuf, i); 19215646Sralph item = makdatum(db->db_pagbuf, i); 19315646Sralph if (item.dptr == NULL) { 19415646Sralph printf("ndbm: split not paired\n"); 19515646Sralph break; 19615646Sralph } 19715646Sralph additem(ovfbuf, item); 19815646Sralph delitem(db->db_pagbuf, i); 19915646Sralph continue; 20015646Sralph } 20115646Sralph i += 2; 20215646Sralph } 20315646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 20415646Sralph (void) write(db->db_pagf, db->db_pagbuf, PBLKSIZ); 20515646Sralph db->db_pagbno = db->db_blkno; 20615646Sralph (void) lseek(db->db_pagf, (db->db_blkno+db->db_hmask+1)*PBLKSIZ, L_SET); 20715646Sralph (void) write(db->db_pagf, ovfbuf, PBLKSIZ); 20815646Sralph setbit(db); 20915646Sralph goto loop; 21015646Sralph } 21115646Sralph 21215646Sralph datum 21315646Sralph dbmfirstkey(db) 21415646Sralph DBM *db; 21515646Sralph { 21615646Sralph 21715646Sralph return (firsthash(db, 0L)); 21815646Sralph } 21915646Sralph 22015646Sralph datum 22115646Sralph dbmnextkey(db, key) 22215646Sralph register DBM *db; 22315646Sralph datum key; 22415646Sralph { 22515646Sralph register i; 22615646Sralph datum item, bitem; 22715646Sralph long hash; 22815646Sralph int f; 22915646Sralph 23015646Sralph hash = dcalchash(key); 23115646Sralph dbm_access(db, hash); 23215646Sralph f = 1; 23315646Sralph for (i=0;; i+=2) { 23415646Sralph item = makdatum(db->db_pagbuf, i); 23515646Sralph if (item.dptr == NULL) 23615646Sralph break; 23715646Sralph if (cmpdatum(key, item) <= 0) 23815646Sralph continue; 23915646Sralph if (f || cmpdatum(bitem, item) < 0) { 24015646Sralph bitem = item; 24115646Sralph f = 0; 24215646Sralph } 24315646Sralph } 24415646Sralph if (f == 0) 24515646Sralph return (bitem); 24615646Sralph hash = hashinc(db, hash); 24715646Sralph if (hash == 0) 24815646Sralph return (item); 24915646Sralph return (firsthash(db, hash)); 25015646Sralph } 25115646Sralph 25215646Sralph static datum 25315646Sralph firsthash(db, hash) 25415646Sralph register DBM *db; 25515646Sralph long hash; 25615646Sralph { 25715646Sralph register i; 25815646Sralph datum item, bitem; 25915646Sralph 26015646Sralph loop: 26115646Sralph dbm_access(db, hash); 26215646Sralph bitem = makdatum(db->db_pagbuf, 0); 26315646Sralph for (i=2;; i+=2) { 26415646Sralph item = makdatum(db->db_pagbuf, i); 26515646Sralph if (item.dptr == NULL) 26615646Sralph break; 26715646Sralph if (cmpdatum(bitem, item) < 0) 26815646Sralph bitem = item; 26915646Sralph } 27015646Sralph if (bitem.dptr != NULL) 27115646Sralph return (bitem); 27215646Sralph hash = hashinc(db, hash); 27315646Sralph if (hash == 0) 27415646Sralph return (item); 27515646Sralph goto loop; 27615646Sralph } 27715646Sralph 27815646Sralph static 27915646Sralph dbm_access(db, hash) 28015646Sralph register DBM *db; 28115646Sralph long hash; 28215646Sralph { 28315646Sralph 28415646Sralph for (db->db_hmask=0;; db->db_hmask=(db->db_hmask<<1)+1) { 28515646Sralph db->db_blkno = hash & db->db_hmask; 28615646Sralph db->db_bitno = db->db_blkno + db->db_hmask; 28715646Sralph if (getbit(db) == 0) 28815646Sralph break; 28915646Sralph } 29015646Sralph if (db->db_blkno != db->db_pagbno) { 29115646Sralph bzero(db->db_pagbuf, PBLKSIZ); 29215646Sralph (void) lseek(db->db_pagf, db->db_blkno*PBLKSIZ, L_SET); 29315646Sralph (void) read(db->db_pagf, db->db_pagbuf, PBLKSIZ); 29415646Sralph chkblk(db->db_pagbuf); 29515646Sralph db->db_pagbno = db->db_blkno; 29615646Sralph } 29715646Sralph } 29815646Sralph 29915646Sralph static 30015646Sralph getbit(db) 30115646Sralph register DBM *db; 30215646Sralph { 30315646Sralph long bn; 30415646Sralph register b, i, n; 30515646Sralph 30615646Sralph 30715646Sralph if (db->db_bitno > db->db_maxbno) 30815646Sralph return (0); 30915646Sralph n = db->db_bitno % BYTESIZ; 31015646Sralph bn = db->db_bitno / BYTESIZ; 31115646Sralph i = bn % DBLKSIZ; 31215646Sralph b = bn / DBLKSIZ; 31315646Sralph if (b != db->db_dirbno) { 31415646Sralph bzero(db->db_dirbuf, DBLKSIZ); 31515646Sralph (void) lseek(db->db_dirf, (long)b*DBLKSIZ, L_SET); 31615646Sralph (void) read(db->db_dirf, db->db_dirbuf, DBLKSIZ); 31715646Sralph db->db_dirbno = b; 31815646Sralph } 31915646Sralph if (db->db_dirbuf[i] & (1<<n)) 32015646Sralph return (1); 32115646Sralph return (0); 32215646Sralph } 32315646Sralph 32415646Sralph static 32515646Sralph setbit(db) 32615646Sralph register DBM *db; 32715646Sralph { 32815646Sralph long bn; 32915646Sralph register i, n, b; 33015646Sralph 33115646Sralph if (dbrdonly(db)) { 33215646Sralph errno = EPERM; 33315646Sralph return (-1); 33415646Sralph } 33515646Sralph if (db->db_bitno > db->db_maxbno) { 33615646Sralph db->db_maxbno = db->db_bitno; 33715646Sralph getbit(db); 33815646Sralph } 33915646Sralph n = db->db_bitno % BYTESIZ; 34015646Sralph bn = db->db_bitno / BYTESIZ; 34115646Sralph i = bn % DBLKSIZ; 34215646Sralph b = bn / DBLKSIZ; 34315646Sralph db->db_dirbuf[i] |= 1<<n; 34415646Sralph (void) lseek(db->db_dirf, (long)b*DBLKSIZ, L_SET); 34515646Sralph (void) write(db->db_dirf, db->db_dirbuf, DBLKSIZ); 34615646Sralph db->db_dirbno = b; 34715646Sralph } 34815646Sralph 34915646Sralph static datum 35015646Sralph makdatum(buf, n) 35115646Sralph char buf[PBLKSIZ]; 35215646Sralph { 35315646Sralph register short *sp; 35415646Sralph register t; 35515646Sralph datum item; 35615646Sralph 35715646Sralph sp = (short *)buf; 35815646Sralph if (n < 0 || n >= sp[0]) 35915646Sralph goto null; 36015646Sralph t = PBLKSIZ; 36115646Sralph if (n > 0) 36215646Sralph t = sp[n+1-1]; 36315646Sralph item.dptr = buf+sp[n+1]; 36415646Sralph item.dsize = t - sp[n+1]; 36515646Sralph return (item); 36615646Sralph 36715646Sralph null: 36815646Sralph item.dptr = NULL; 36915646Sralph item.dsize = 0; 37015646Sralph return (item); 37115646Sralph } 37215646Sralph 37315646Sralph static 37415646Sralph cmpdatum(d1, d2) 37515646Sralph datum d1, d2; 37615646Sralph { 37715646Sralph register n; 37815646Sralph register char *p1, *p2; 37915646Sralph 38015646Sralph n = d1.dsize; 38115646Sralph if (n != d2.dsize) 38215646Sralph return (n - d2.dsize); 38315646Sralph if (n == 0) 38415646Sralph return (0); 38515646Sralph p1 = d1.dptr; 38615646Sralph p2 = d2.dptr; 38715646Sralph do 38815646Sralph if (*p1++ != *p2++) 38915646Sralph return (*--p1 - *--p2); 39015646Sralph while (--n); 39115646Sralph return (0); 39215646Sralph } 39315646Sralph 39415646Sralph static int hitab[16] 39515646Sralph /* ken's 39615646Sralph { 39715646Sralph 055,043,036,054,063,014,004,005, 39815646Sralph 010,064,077,000,035,027,025,071, 39915646Sralph }; 40015646Sralph */ 40115646Sralph = { 61, 57, 53, 49, 45, 41, 37, 33, 40215646Sralph 29, 25, 21, 17, 13, 9, 5, 1, 40315646Sralph }; 40415646Sralph static long hltab[64] 40515646Sralph = { 40615646Sralph 06100151277L,06106161736L,06452611562L,05001724107L, 40715646Sralph 02614772546L,04120731531L,04665262210L,07347467531L, 40815646Sralph 06735253126L,06042345173L,03072226605L,01464164730L, 40915646Sralph 03247435524L,07652510057L,01546775256L,05714532133L, 41015646Sralph 06173260402L,07517101630L,02431460343L,01743245566L, 41115646Sralph 00261675137L,02433103631L,03421772437L,04447707466L, 41215646Sralph 04435620103L,03757017115L,03641531772L,06767633246L, 41315646Sralph 02673230344L,00260612216L,04133454451L,00615531516L, 41415646Sralph 06137717526L,02574116560L,02304023373L,07061702261L, 41515646Sralph 05153031405L,05322056705L,07401116734L,06552375715L, 41615646Sralph 06165233473L,05311063631L,01212221723L,01052267235L, 41715646Sralph 06000615237L,01075222665L,06330216006L,04402355630L, 41815646Sralph 01451177262L,02000133436L,06025467062L,07121076461L, 41915646Sralph 03123433522L,01010635225L,01716177066L,05161746527L, 42015646Sralph 01736635071L,06243505026L,03637211610L,01756474365L, 42115646Sralph 04723077174L,03642763134L,05750130273L,03655541561L, 42215646Sralph }; 42315646Sralph 42415646Sralph static long 42515646Sralph hashinc(db, hash) 42615646Sralph register DBM *db; 42715646Sralph long hash; 42815646Sralph { 42915646Sralph long bit; 43015646Sralph 43115646Sralph hash &= db->db_hmask; 43215646Sralph bit = db->db_hmask+1; 43315646Sralph for (;;) { 43415646Sralph bit >>= 1; 43515646Sralph if (bit == 0) 43615646Sralph return (0L); 43715646Sralph if ((hash&bit) == 0) 43815646Sralph return (hash|bit); 43915646Sralph hash &= ~bit; 44015646Sralph } 44115646Sralph } 44215646Sralph 44315646Sralph static long 44415646Sralph dcalchash(item) 44515646Sralph datum item; 44615646Sralph { 44715646Sralph register i, j, f; 44815646Sralph long hashl; 44915646Sralph int hashi; 45015646Sralph 45115646Sralph hashl = 0; 45215646Sralph hashi = 0; 45315646Sralph for (i=0; i<item.dsize; i++) { 45415646Sralph f = item.dptr[i]; 45515646Sralph for (j=0; j<BYTESIZ; j+=4) { 45615646Sralph hashi += hitab[f&017]; 45715646Sralph hashl += hltab[hashi&63]; 45815646Sralph f >>= 4; 45915646Sralph } 46015646Sralph } 46115646Sralph return (hashl); 46215646Sralph } 46315646Sralph 46415646Sralph static 46515646Sralph delitem(buf, n) 46615646Sralph char buf[PBLKSIZ]; 46715646Sralph { 46815646Sralph register short *sp; 46915646Sralph register i1, i2, i3; 47015646Sralph 47115646Sralph sp = (short *)buf; 47215646Sralph if (n < 0 || n >= sp[0]) 47315646Sralph goto bad; 47415646Sralph i1 = sp[n+1]; 47515646Sralph i2 = PBLKSIZ; 47615646Sralph if (n > 0) 47715646Sralph i2 = sp[n+1-1]; 47815646Sralph i3 = sp[sp[0]+1-1]; 47915646Sralph if (i2 > i1) 48015646Sralph while (i1 > i3) { 48115646Sralph i1--; 48215646Sralph i2--; 48315646Sralph buf[i2] = buf[i1]; 48415646Sralph buf[i1] = 0; 48515646Sralph } 48615646Sralph i2 -= i1; 48715646Sralph for (i1=n+1; i1<sp[0]; i1++) 48815646Sralph sp[i1+1-1] = sp[i1+1] + i2; 48915646Sralph sp[0]--; 49015646Sralph sp[sp[0]+1] = 0; 49115646Sralph return; 49215646Sralph 49315646Sralph bad: 49415646Sralph printf("ndbm: bad delitem\n"); 49515646Sralph abort(); 49615646Sralph } 49715646Sralph 49815646Sralph static 49915646Sralph additem(buf, item) 50015646Sralph char buf[PBLKSIZ]; 50115646Sralph datum item; 50215646Sralph { 50315646Sralph register short *sp; 50415646Sralph register i1, i2; 50515646Sralph 50615646Sralph sp = (short *)buf; 50715646Sralph i1 = PBLKSIZ; 50815646Sralph if (sp[0] > 0) 50915646Sralph i1 = sp[sp[0]+1-1]; 51015646Sralph i1 -= item.dsize; 51115646Sralph i2 = (sp[0]+2) * sizeof(short); 51215646Sralph if (i1 <= i2) 51315646Sralph return (-1); 51415646Sralph sp[sp[0]+1] = i1; 51515646Sralph for (i2=0; i2<item.dsize; i2++) { 51615646Sralph buf[i1] = item.dptr[i2]; 51715646Sralph i1++; 51815646Sralph } 51915646Sralph sp[0]++; 52015646Sralph return (sp[0]-1); 52115646Sralph } 52215646Sralph 52315646Sralph static 52415646Sralph chkblk(buf) 52515646Sralph char buf[PBLKSIZ]; 52615646Sralph { 52715646Sralph register short *sp; 52815646Sralph register t, i; 52915646Sralph 53015646Sralph sp = (short *)buf; 53115646Sralph t = PBLKSIZ; 53215646Sralph for (i=0; i<sp[0]; i++) { 53315646Sralph if (sp[i+1] > t) 53415646Sralph goto bad; 53515646Sralph t = sp[i+1]; 53615646Sralph } 53715646Sralph if (t < (sp[0]+1)*sizeof(short)) 53815646Sralph goto bad; 53915646Sralph return; 54015646Sralph 54115646Sralph bad: 54215646Sralph printf("ndbm: bad block\n"); 54315646Sralph abort(); 54415646Sralph bzero(buf, PBLKSIZ); 54515646Sralph } 546