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