113305Ssam #ifndef lint
2*23571Smckusick static char sccsid[] = "@(#)dbm.c 4.5 (Berkeley) 06/19/85";
313305Ssam #endif
413305Ssam
513305Ssam #include "dbm.h"
6*23571Smckusick #undef NULL
713305Ssam #include <sys/types.h>
8*23571Smckusick #undef setbit
913305Ssam #include <sys/stat.h>
1013305Ssam
dbminit(file)1113305Ssam dbminit(file)
1213305Ssam char *file;
1313305Ssam {
1413305Ssam struct stat statb;
1513305Ssam
1613305Ssam dbrdonly = 0;
1713305Ssam strcpy(pagbuf, file);
1813305Ssam strcat(pagbuf, ".pag");
1913305Ssam pagf = open(pagbuf, 2);
2013305Ssam if (pagf < 0) {
2113305Ssam pagf = open(pagbuf, 0);
2213305Ssam dbrdonly = 1;
2313305Ssam }
2413305Ssam
2513305Ssam strcpy(pagbuf, file);
2613305Ssam strcat(pagbuf, ".dir");
2713305Ssam dirf = open(pagbuf, 2);
2813305Ssam if (dirf < 0) {
2913305Ssam dirf = open(pagbuf, 0);
3013305Ssam dbrdonly = 1;
3113305Ssam }
3213305Ssam if(pagf < 0 || dirf < 0) {
3322023Ssam printf("dbm: %s: cannot open database\n", file);
3413305Ssam return(-1);
3513305Ssam }
3613305Ssam fstat(dirf, &statb);
3713305Ssam maxbno = statb.st_size*BYTESIZ-1;
3813305Ssam return(0);
3913305Ssam }
4013305Ssam
4113305Ssam long
forder(key)4213305Ssam forder(key)
4313305Ssam datum key;
4413305Ssam {
4513305Ssam long hash;
4613305Ssam
4713305Ssam hash = calchash(key);
4813305Ssam for(hmask=0;; hmask=(hmask<<1)+1) {
4913305Ssam blkno = hash & hmask;
5013305Ssam bitno = blkno + hmask;
5113305Ssam if(getbit() == 0)
5213305Ssam break;
5313305Ssam }
5413305Ssam return(blkno);
5513305Ssam }
5613305Ssam
5713305Ssam datum
fetch(key)5813305Ssam fetch(key)
5913305Ssam datum key;
6013305Ssam {
6113305Ssam register i;
6213305Ssam datum item;
6313305Ssam
6413305Ssam dbm_access(calchash(key));
6513305Ssam for(i=0;; i+=2) {
6613305Ssam item = makdatum(pagbuf, i);
6713305Ssam if(item.dptr == NULL)
6813305Ssam return(item);
6913305Ssam if(cmpdatum(key, item) == 0) {
7013305Ssam item = makdatum(pagbuf, i+1);
7113305Ssam if(item.dptr == NULL)
7222023Ssam printf("dbm: items not in pairs\n");
7313305Ssam return(item);
7413305Ssam }
7513305Ssam }
7613305Ssam }
7713305Ssam
delete(key)7813305Ssam delete(key)
7913305Ssam datum key;
8013305Ssam {
8113305Ssam register i;
8213305Ssam datum item;
8313305Ssam
8413305Ssam if (dbrdonly)
8513305Ssam return -1;
8613305Ssam dbm_access(calchash(key));
8713305Ssam for(i=0;; i+=2) {
8813305Ssam item = makdatum(pagbuf, i);
8913305Ssam if(item.dptr == NULL)
9013305Ssam return(-1);
9113305Ssam if(cmpdatum(key, item) == 0) {
9213305Ssam delitem(pagbuf, i);
9313305Ssam delitem(pagbuf, i);
9413305Ssam break;
9513305Ssam }
9613305Ssam }
9713305Ssam lseek(pagf, blkno*PBLKSIZ, 0);
9813305Ssam write(pagf, pagbuf, PBLKSIZ);
9913305Ssam return(0);
10013305Ssam }
10113305Ssam
store(key,dat)10213305Ssam store(key, dat)
10313305Ssam datum key, dat;
10413305Ssam {
10513305Ssam register i;
10613305Ssam datum item;
10713305Ssam char ovfbuf[PBLKSIZ];
10813305Ssam
10913305Ssam if (dbrdonly)
11013305Ssam return -1;
11113305Ssam loop:
11213305Ssam dbm_access(calchash(key));
11313305Ssam for(i=0;; i+=2) {
11413305Ssam item = makdatum(pagbuf, i);
11513305Ssam if(item.dptr == NULL)
11613305Ssam break;
11713305Ssam if(cmpdatum(key, item) == 0) {
11813305Ssam delitem(pagbuf, i);
11913305Ssam delitem(pagbuf, i);
12013305Ssam break;
12113305Ssam }
12213305Ssam }
12313305Ssam i = additem(pagbuf, key);
12413305Ssam if(i < 0)
12513305Ssam goto split;
12613305Ssam if(additem(pagbuf, dat) < 0) {
12713305Ssam delitem(pagbuf, i);
12813305Ssam goto split;
12913305Ssam }
13013305Ssam lseek(pagf, blkno*PBLKSIZ, 0);
13113305Ssam write(pagf, pagbuf, PBLKSIZ);
13213305Ssam return (0);
13313305Ssam
13413305Ssam split:
13518610Sralph if(key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) {
13622023Ssam printf("dbm: entry too big\n");
13713305Ssam return (-1);
13813305Ssam }
13913305Ssam clrbuf(ovfbuf, PBLKSIZ);
14013305Ssam for(i=0;;) {
14113305Ssam item = makdatum(pagbuf, i);
14213305Ssam if(item.dptr == NULL)
14313305Ssam break;
14413305Ssam if(calchash(item) & (hmask+1)) {
14513305Ssam additem(ovfbuf, item);
14613305Ssam delitem(pagbuf, i);
14713305Ssam item = makdatum(pagbuf, i);
14813305Ssam if(item.dptr == NULL) {
14922023Ssam printf("dbm: split not paired\n");
15013305Ssam break;
15113305Ssam }
15213305Ssam additem(ovfbuf, item);
15313305Ssam delitem(pagbuf, i);
15413305Ssam continue;
15513305Ssam }
15613305Ssam i += 2;
15713305Ssam }
15813305Ssam lseek(pagf, blkno*PBLKSIZ, 0);
15913305Ssam write(pagf, pagbuf, PBLKSIZ);
16013305Ssam lseek(pagf, (blkno+hmask+1)*PBLKSIZ, 0);
16113305Ssam write(pagf, ovfbuf, PBLKSIZ);
16213305Ssam setbit();
16313305Ssam goto loop;
16413305Ssam }
16513305Ssam
16613305Ssam datum
firstkey()16713305Ssam firstkey()
16813305Ssam {
16913305Ssam return(firsthash(0L));
17013305Ssam }
17113305Ssam
17213305Ssam datum
nextkey(key)17313305Ssam nextkey(key)
17413305Ssam datum key;
17513305Ssam {
17613305Ssam register i;
17713305Ssam datum item, bitem;
17813305Ssam long hash;
17913305Ssam int f;
18013305Ssam
18113305Ssam hash = calchash(key);
18213305Ssam dbm_access(hash);
18313305Ssam f = 1;
18413305Ssam for(i=0;; i+=2) {
18513305Ssam item = makdatum(pagbuf, i);
18613305Ssam if(item.dptr == NULL)
18713305Ssam break;
18813305Ssam if(cmpdatum(key, item) <= 0)
18913305Ssam continue;
19013305Ssam if(f || cmpdatum(bitem, item) < 0) {
19113305Ssam bitem = item;
19213305Ssam f = 0;
19313305Ssam }
19413305Ssam }
19513305Ssam if(f == 0)
19613305Ssam return(bitem);
19713305Ssam hash = hashinc(hash);
19813305Ssam if(hash == 0)
19913305Ssam return(item);
20013305Ssam return(firsthash(hash));
20113305Ssam }
20213305Ssam
20313305Ssam datum
firsthash(hash)20413305Ssam firsthash(hash)
20513305Ssam long hash;
20613305Ssam {
20713305Ssam register i;
20813305Ssam datum item, bitem;
20913305Ssam
21013305Ssam loop:
21113305Ssam dbm_access(hash);
21213305Ssam bitem = makdatum(pagbuf, 0);
21313305Ssam for(i=2;; i+=2) {
21413305Ssam item = makdatum(pagbuf, i);
21513305Ssam if(item.dptr == NULL)
21613305Ssam break;
21713305Ssam if(cmpdatum(bitem, item) < 0)
21813305Ssam bitem = item;
21913305Ssam }
22013305Ssam if(bitem.dptr != NULL)
22113305Ssam return(bitem);
22213305Ssam hash = hashinc(hash);
22313305Ssam if(hash == 0)
22413305Ssam return(item);
22513305Ssam goto loop;
22613305Ssam }
22713305Ssam
dbm_access(hash)22813305Ssam dbm_access(hash)
22913305Ssam long hash;
23013305Ssam {
23113305Ssam static long oldb = -1;
23213305Ssam
23313305Ssam for(hmask=0;; hmask=(hmask<<1)+1) {
23413305Ssam blkno = hash & hmask;
23513305Ssam bitno = blkno + hmask;
23613305Ssam if(getbit() == 0)
23713305Ssam break;
23813305Ssam }
23913305Ssam if(blkno != oldb) {
24013305Ssam clrbuf(pagbuf, PBLKSIZ);
24113305Ssam lseek(pagf, blkno*PBLKSIZ, 0);
24213305Ssam read(pagf, pagbuf, PBLKSIZ);
24313305Ssam chkblk(pagbuf);
24413305Ssam oldb = blkno;
24513305Ssam }
24613305Ssam }
24713305Ssam
getbit()24813305Ssam getbit()
24913305Ssam {
25013305Ssam long bn;
25113305Ssam register b, i, n;
25213305Ssam static oldb = -1;
25313305Ssam
25413305Ssam if(bitno > maxbno)
25513305Ssam return(0);
25613305Ssam n = bitno % BYTESIZ;
25713305Ssam bn = bitno / BYTESIZ;
25813305Ssam i = bn % DBLKSIZ;
25913305Ssam b = bn / DBLKSIZ;
26013305Ssam if(b != oldb) {
26113305Ssam clrbuf(dirbuf, DBLKSIZ);
26213305Ssam lseek(dirf, (long)b*DBLKSIZ, 0);
26313305Ssam read(dirf, dirbuf, DBLKSIZ);
26413305Ssam oldb = b;
26513305Ssam }
26613305Ssam if(dirbuf[i] & (1<<n))
26713305Ssam return(1);
26813305Ssam return(0);
26913305Ssam }
27013305Ssam
setbit()27113305Ssam setbit()
27213305Ssam {
27313305Ssam long bn;
27413305Ssam register i, n, b;
27513305Ssam
27613305Ssam if (dbrdonly)
27713305Ssam return -1;
27813305Ssam if(bitno > maxbno) {
27913305Ssam maxbno = bitno;
28013305Ssam getbit();
28113305Ssam }
28213305Ssam n = bitno % BYTESIZ;
28313305Ssam bn = bitno / BYTESIZ;
28413305Ssam i = bn % DBLKSIZ;
28513305Ssam b = bn / DBLKSIZ;
28613305Ssam dirbuf[i] |= 1<<n;
28713305Ssam lseek(dirf, (long)b*DBLKSIZ, 0);
28813305Ssam write(dirf, dirbuf, DBLKSIZ);
28913305Ssam }
29013305Ssam
clrbuf(cp,n)29113305Ssam clrbuf(cp, n)
29213305Ssam register char *cp;
29313305Ssam register n;
29413305Ssam {
29513305Ssam
29613305Ssam do
29713305Ssam *cp++ = 0;
29813305Ssam while(--n);
29913305Ssam }
30013305Ssam
30113305Ssam datum
makdatum(buf,n)30213305Ssam makdatum(buf, n)
30313305Ssam char buf[PBLKSIZ];
30413305Ssam {
30513305Ssam register short *sp;
30613305Ssam register t;
30713305Ssam datum item;
30813305Ssam
30913305Ssam sp = (short *)buf;
31013305Ssam if(n < 0 || n >= sp[0])
31113305Ssam goto null;
31213305Ssam t = PBLKSIZ;
31313305Ssam if(n > 0)
31413305Ssam t = sp[n+1-1];
31513305Ssam item.dptr = buf+sp[n+1];
31613305Ssam item.dsize = t - sp[n+1];
31713305Ssam return(item);
31813305Ssam
31913305Ssam null:
32013305Ssam item.dptr = NULL;
32113305Ssam item.dsize = 0;
32213305Ssam return(item);
32313305Ssam }
32413305Ssam
cmpdatum(d1,d2)32513305Ssam cmpdatum(d1, d2)
32613305Ssam datum d1, d2;
32713305Ssam {
32813305Ssam register n;
32913305Ssam register char *p1, *p2;
33013305Ssam
33113305Ssam n = d1.dsize;
33213305Ssam if(n != d2.dsize)
33313305Ssam return(n - d2.dsize);
33413305Ssam if(n == 0)
33513305Ssam return(0);
33613305Ssam p1 = d1.dptr;
33713305Ssam p2 = d2.dptr;
33813305Ssam do
33913305Ssam if(*p1++ != *p2++)
34013305Ssam return(*--p1 - *--p2);
34113305Ssam while(--n);
34213305Ssam return(0);
34313305Ssam }
34413305Ssam
34513305Ssam int hitab[16]
34613305Ssam /* ken's
34713305Ssam {
34813305Ssam 055,043,036,054,063,014,004,005,
34913305Ssam 010,064,077,000,035,027,025,071,
35013305Ssam };
35113305Ssam */
35213305Ssam = { 61, 57, 53, 49, 45, 41, 37, 33,
35313305Ssam 29, 25, 21, 17, 13, 9, 5, 1,
35413305Ssam };
35513305Ssam long hltab[64]
35613305Ssam = {
35713305Ssam 06100151277L,06106161736L,06452611562L,05001724107L,
35813305Ssam 02614772546L,04120731531L,04665262210L,07347467531L,
35913305Ssam 06735253126L,06042345173L,03072226605L,01464164730L,
36013305Ssam 03247435524L,07652510057L,01546775256L,05714532133L,
36113305Ssam 06173260402L,07517101630L,02431460343L,01743245566L,
36213305Ssam 00261675137L,02433103631L,03421772437L,04447707466L,
36313305Ssam 04435620103L,03757017115L,03641531772L,06767633246L,
36413305Ssam 02673230344L,00260612216L,04133454451L,00615531516L,
36513305Ssam 06137717526L,02574116560L,02304023373L,07061702261L,
36613305Ssam 05153031405L,05322056705L,07401116734L,06552375715L,
36713305Ssam 06165233473L,05311063631L,01212221723L,01052267235L,
36813305Ssam 06000615237L,01075222665L,06330216006L,04402355630L,
36913305Ssam 01451177262L,02000133436L,06025467062L,07121076461L,
37013305Ssam 03123433522L,01010635225L,01716177066L,05161746527L,
37113305Ssam 01736635071L,06243505026L,03637211610L,01756474365L,
37213305Ssam 04723077174L,03642763134L,05750130273L,03655541561L,
37313305Ssam };
37413305Ssam
37513305Ssam long
hashinc(hash)37613305Ssam hashinc(hash)
37713305Ssam long hash;
37813305Ssam {
37913305Ssam long bit;
38013305Ssam
38113305Ssam hash &= hmask;
38213305Ssam bit = hmask+1;
38313305Ssam for(;;) {
38413305Ssam bit >>= 1;
38513305Ssam if(bit == 0)
38613305Ssam return(0L);
38713305Ssam if((hash&bit) == 0)
38813305Ssam return(hash|bit);
38913305Ssam hash &= ~bit;
39013305Ssam }
39113305Ssam }
39213305Ssam
39313305Ssam long
calchash(item)39413305Ssam calchash(item)
39513305Ssam datum item;
39613305Ssam {
39713305Ssam register i, j, f;
39813305Ssam long hashl;
39913305Ssam int hashi;
40013305Ssam
40113305Ssam hashl = 0;
40213305Ssam hashi = 0;
40313305Ssam for(i=0; i<item.dsize; i++) {
40413305Ssam f = item.dptr[i];
40513305Ssam for(j=0; j<BYTESIZ; j+=4) {
40613305Ssam hashi += hitab[f&017];
40713305Ssam hashl += hltab[hashi&63];
40813305Ssam f >>= 4;
40913305Ssam }
41013305Ssam }
41113305Ssam return(hashl);
41213305Ssam }
41313305Ssam
delitem(buf,n)41413305Ssam delitem(buf, n)
41513305Ssam char buf[PBLKSIZ];
41613305Ssam {
41713305Ssam register short *sp;
41813305Ssam register i1, i2, i3;
41913305Ssam
42013305Ssam sp = (short *)buf;
42113305Ssam if(n < 0 || n >= sp[0])
42213305Ssam goto bad;
42313305Ssam i1 = sp[n+1];
42413305Ssam i2 = PBLKSIZ;
42513305Ssam if(n > 0)
42613305Ssam i2 = sp[n+1-1];
42713305Ssam i3 = sp[sp[0]+1-1];
42813305Ssam if(i2 > i1)
42913305Ssam while(i1 > i3) {
43013305Ssam i1--;
43113305Ssam i2--;
43213305Ssam buf[i2] = buf[i1];
43313305Ssam buf[i1] = 0;
43413305Ssam }
43513305Ssam i2 -= i1;
43613305Ssam for(i1=n+1; i1<sp[0]; i1++)
43713305Ssam sp[i1+1-1] = sp[i1+1] + i2;
43813305Ssam sp[0]--;
43913305Ssam sp[sp[0]+1] = 0;
44013305Ssam return;
44113305Ssam
44213305Ssam bad:
44322023Ssam printf("dbm: bad delitem\n");
44413305Ssam abort();
44513305Ssam }
44613305Ssam
additem(buf,item)44713305Ssam additem(buf, item)
44813305Ssam char buf[PBLKSIZ];
44913305Ssam datum item;
45013305Ssam {
45113305Ssam register short *sp;
45213305Ssam register i1, i2;
45313305Ssam
45413305Ssam sp = (short *)buf;
45513305Ssam i1 = PBLKSIZ;
45613305Ssam if(sp[0] > 0)
45713305Ssam i1 = sp[sp[0]+1-1];
45813305Ssam i1 -= item.dsize;
45913305Ssam i2 = (sp[0]+2) * sizeof(short);
46013305Ssam if(i1 <= i2)
46113305Ssam return(-1);
46213305Ssam sp[sp[0]+1] = i1;
46313305Ssam for(i2=0; i2<item.dsize; i2++) {
46413305Ssam buf[i1] = item.dptr[i2];
46513305Ssam i1++;
46613305Ssam }
46713305Ssam sp[0]++;
46813305Ssam return(sp[0]-1);
46913305Ssam }
47013305Ssam
chkblk(buf)47113305Ssam chkblk(buf)
47213305Ssam char buf[PBLKSIZ];
47313305Ssam {
47413305Ssam register short *sp;
47513305Ssam register t, i;
47613305Ssam
47713305Ssam sp = (short *)buf;
47813305Ssam t = PBLKSIZ;
47913305Ssam for(i=0; i<sp[0]; i++) {
48013305Ssam if(sp[i+1] > t)
48113305Ssam goto bad;
48213305Ssam t = sp[i+1];
48313305Ssam }
48413305Ssam if(t < (sp[0]+1)*sizeof(short))
48513305Ssam goto bad;
48613305Ssam return;
48713305Ssam
48813305Ssam bad:
48921874Sbloom printf("dbm: bad block\n");
49013305Ssam abort();
49113305Ssam clrbuf(buf, PBLKSIZ);
49213305Ssam }
493