xref: /csrg-svn/old/libdbm/dbm.c (revision 23571)
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