xref: /csrg-svn/old/libdbm/dbm.c (revision 13305)
1*13305Ssam #ifndef lint
2*13305Ssam static char sccsid[] = "@(#)dbm.c	4.1 (Berkeley) 06/27/83";
3*13305Ssam #endif
4*13305Ssam 
5*13305Ssam #include	"dbm.h"
6*13305Ssam #include	<sys/types.h>
7*13305Ssam #include	<sys/stat.h>
8*13305Ssam 
9*13305Ssam dbminit(file)
10*13305Ssam char *file;
11*13305Ssam {
12*13305Ssam 	struct stat statb;
13*13305Ssam 
14*13305Ssam 	dbrdonly = 0;
15*13305Ssam 	strcpy(pagbuf, file);
16*13305Ssam 	strcat(pagbuf, ".pag");
17*13305Ssam 	pagf = open(pagbuf, 2);
18*13305Ssam 	if (pagf < 0) {
19*13305Ssam 		pagf = open(pagbuf, 0);
20*13305Ssam 		dbrdonly = 1;
21*13305Ssam 	}
22*13305Ssam 
23*13305Ssam 	strcpy(pagbuf, file);
24*13305Ssam 	strcat(pagbuf, ".dir");
25*13305Ssam 	dirf = open(pagbuf, 2);
26*13305Ssam 	if (dirf < 0) {
27*13305Ssam 		dirf = open(pagbuf, 0);
28*13305Ssam 		dbrdonly = 1;
29*13305Ssam 	}
30*13305Ssam 	if(pagf < 0 || dirf < 0) {
31*13305Ssam 		printf("cannot open database %s\n", file);
32*13305Ssam 		return(-1);
33*13305Ssam 	}
34*13305Ssam 	fstat(dirf, &statb);
35*13305Ssam 	maxbno = statb.st_size*BYTESIZ-1;
36*13305Ssam 	return(0);
37*13305Ssam }
38*13305Ssam 
39*13305Ssam long
40*13305Ssam forder(key)
41*13305Ssam datum key;
42*13305Ssam {
43*13305Ssam 	long hash;
44*13305Ssam 
45*13305Ssam 	hash = calchash(key);
46*13305Ssam 	for(hmask=0;; hmask=(hmask<<1)+1) {
47*13305Ssam 		blkno = hash & hmask;
48*13305Ssam 		bitno = blkno + hmask;
49*13305Ssam 		if(getbit() == 0)
50*13305Ssam 			break;
51*13305Ssam 	}
52*13305Ssam 	return(blkno);
53*13305Ssam }
54*13305Ssam 
55*13305Ssam datum
56*13305Ssam fetch(key)
57*13305Ssam datum key;
58*13305Ssam {
59*13305Ssam 	register i;
60*13305Ssam 	datum item;
61*13305Ssam 
62*13305Ssam 	dbm_access(calchash(key));
63*13305Ssam 	for(i=0;; i+=2) {
64*13305Ssam 		item = makdatum(pagbuf, i);
65*13305Ssam 		if(item.dptr == NULL)
66*13305Ssam 			return(item);
67*13305Ssam 		if(cmpdatum(key, item) == 0) {
68*13305Ssam 			item = makdatum(pagbuf, i+1);
69*13305Ssam 			if(item.dptr == NULL)
70*13305Ssam 				printf("items not in pairs\n");
71*13305Ssam 			return(item);
72*13305Ssam 		}
73*13305Ssam 	}
74*13305Ssam }
75*13305Ssam 
76*13305Ssam delete(key)
77*13305Ssam datum key;
78*13305Ssam {
79*13305Ssam 	register i;
80*13305Ssam 	datum item;
81*13305Ssam 
82*13305Ssam 	if (dbrdonly)
83*13305Ssam 		return -1;
84*13305Ssam 	dbm_access(calchash(key));
85*13305Ssam 	for(i=0;; i+=2) {
86*13305Ssam 		item = makdatum(pagbuf, i);
87*13305Ssam 		if(item.dptr == NULL)
88*13305Ssam 			return(-1);
89*13305Ssam 		if(cmpdatum(key, item) == 0) {
90*13305Ssam 			delitem(pagbuf, i);
91*13305Ssam 			delitem(pagbuf, i);
92*13305Ssam 			break;
93*13305Ssam 		}
94*13305Ssam 	}
95*13305Ssam 	lseek(pagf, blkno*PBLKSIZ, 0);
96*13305Ssam 	write(pagf, pagbuf, PBLKSIZ);
97*13305Ssam 	return(0);
98*13305Ssam }
99*13305Ssam 
100*13305Ssam store(key, dat)
101*13305Ssam datum key, dat;
102*13305Ssam {
103*13305Ssam 	register i;
104*13305Ssam 	datum item;
105*13305Ssam 	char ovfbuf[PBLKSIZ];
106*13305Ssam 
107*13305Ssam 	if (dbrdonly)
108*13305Ssam 		return -1;
109*13305Ssam loop:
110*13305Ssam 	dbm_access(calchash(key));
111*13305Ssam 	for(i=0;; i+=2) {
112*13305Ssam 		item = makdatum(pagbuf, i);
113*13305Ssam 		if(item.dptr == NULL)
114*13305Ssam 			break;
115*13305Ssam 		if(cmpdatum(key, item) == 0) {
116*13305Ssam 			delitem(pagbuf, i);
117*13305Ssam 			delitem(pagbuf, i);
118*13305Ssam 			break;
119*13305Ssam 		}
120*13305Ssam 	}
121*13305Ssam 	i = additem(pagbuf, key);
122*13305Ssam 	if(i < 0)
123*13305Ssam 		goto split;
124*13305Ssam 	if(additem(pagbuf, dat) < 0) {
125*13305Ssam 		delitem(pagbuf, i);
126*13305Ssam 		goto split;
127*13305Ssam 	}
128*13305Ssam 	lseek(pagf, blkno*PBLKSIZ, 0);
129*13305Ssam 	write(pagf, pagbuf, PBLKSIZ);
130*13305Ssam 	return (0);
131*13305Ssam 
132*13305Ssam split:
133*13305Ssam 	if(key.dsize+dat.dsize+2*sizeof(short) >= PBLKSIZ) {
134*13305Ssam 		printf("entry too big\n");
135*13305Ssam 		return (-1);
136*13305Ssam 	}
137*13305Ssam 	clrbuf(ovfbuf, PBLKSIZ);
138*13305Ssam 	for(i=0;;) {
139*13305Ssam 		item = makdatum(pagbuf, i);
140*13305Ssam 		if(item.dptr == NULL)
141*13305Ssam 			break;
142*13305Ssam 		if(calchash(item) & (hmask+1)) {
143*13305Ssam 			additem(ovfbuf, item);
144*13305Ssam 			delitem(pagbuf, i);
145*13305Ssam 			item = makdatum(pagbuf, i);
146*13305Ssam 			if(item.dptr == NULL) {
147*13305Ssam 				printf("split not paired\n");
148*13305Ssam 				break;
149*13305Ssam 			}
150*13305Ssam 			additem(ovfbuf, item);
151*13305Ssam 			delitem(pagbuf, i);
152*13305Ssam 			continue;
153*13305Ssam 		}
154*13305Ssam 		i += 2;
155*13305Ssam 	}
156*13305Ssam 	lseek(pagf, blkno*PBLKSIZ, 0);
157*13305Ssam 	write(pagf, pagbuf, PBLKSIZ);
158*13305Ssam 	lseek(pagf, (blkno+hmask+1)*PBLKSIZ, 0);
159*13305Ssam 	write(pagf, ovfbuf, PBLKSIZ);
160*13305Ssam 	setbit();
161*13305Ssam 	goto loop;
162*13305Ssam }
163*13305Ssam 
164*13305Ssam datum
165*13305Ssam firstkey()
166*13305Ssam {
167*13305Ssam 	return(firsthash(0L));
168*13305Ssam }
169*13305Ssam 
170*13305Ssam datum
171*13305Ssam nextkey(key)
172*13305Ssam datum key;
173*13305Ssam {
174*13305Ssam 	register i;
175*13305Ssam 	datum item, bitem;
176*13305Ssam 	long hash;
177*13305Ssam 	int f;
178*13305Ssam 
179*13305Ssam 	hash = calchash(key);
180*13305Ssam 	dbm_access(hash);
181*13305Ssam 	f = 1;
182*13305Ssam 	for(i=0;; i+=2) {
183*13305Ssam 		item = makdatum(pagbuf, i);
184*13305Ssam 		if(item.dptr == NULL)
185*13305Ssam 			break;
186*13305Ssam 		if(cmpdatum(key, item) <= 0)
187*13305Ssam 			continue;
188*13305Ssam 		if(f || cmpdatum(bitem, item) < 0) {
189*13305Ssam 			bitem = item;
190*13305Ssam 			f = 0;
191*13305Ssam 		}
192*13305Ssam 	}
193*13305Ssam 	if(f == 0)
194*13305Ssam 		return(bitem);
195*13305Ssam 	hash = hashinc(hash);
196*13305Ssam 	if(hash == 0)
197*13305Ssam 		return(item);
198*13305Ssam 	return(firsthash(hash));
199*13305Ssam }
200*13305Ssam 
201*13305Ssam datum
202*13305Ssam firsthash(hash)
203*13305Ssam long hash;
204*13305Ssam {
205*13305Ssam 	register i;
206*13305Ssam 	datum item, bitem;
207*13305Ssam 
208*13305Ssam loop:
209*13305Ssam 	dbm_access(hash);
210*13305Ssam 	bitem = makdatum(pagbuf, 0);
211*13305Ssam 	for(i=2;; i+=2) {
212*13305Ssam 		item = makdatum(pagbuf, i);
213*13305Ssam 		if(item.dptr == NULL)
214*13305Ssam 			break;
215*13305Ssam 		if(cmpdatum(bitem, item) < 0)
216*13305Ssam 			bitem = item;
217*13305Ssam 	}
218*13305Ssam 	if(bitem.dptr != NULL)
219*13305Ssam 		return(bitem);
220*13305Ssam 	hash = hashinc(hash);
221*13305Ssam 	if(hash == 0)
222*13305Ssam 		return(item);
223*13305Ssam 	goto loop;
224*13305Ssam }
225*13305Ssam 
226*13305Ssam dbm_access(hash)
227*13305Ssam long hash;
228*13305Ssam {
229*13305Ssam 	static long oldb = -1;
230*13305Ssam 
231*13305Ssam 	for(hmask=0;; hmask=(hmask<<1)+1) {
232*13305Ssam 		blkno = hash & hmask;
233*13305Ssam 		bitno = blkno + hmask;
234*13305Ssam 		if(getbit() == 0)
235*13305Ssam 			break;
236*13305Ssam 	}
237*13305Ssam 	if(blkno != oldb) {
238*13305Ssam 		clrbuf(pagbuf, PBLKSIZ);
239*13305Ssam 		lseek(pagf, blkno*PBLKSIZ, 0);
240*13305Ssam 		read(pagf, pagbuf, PBLKSIZ);
241*13305Ssam 		chkblk(pagbuf);
242*13305Ssam 		oldb = blkno;
243*13305Ssam 	}
244*13305Ssam }
245*13305Ssam 
246*13305Ssam getbit()
247*13305Ssam {
248*13305Ssam 	long bn;
249*13305Ssam 	register b, i, n;
250*13305Ssam 	static oldb = -1;
251*13305Ssam 
252*13305Ssam 	if(bitno > maxbno)
253*13305Ssam 		return(0);
254*13305Ssam 	n = bitno % BYTESIZ;
255*13305Ssam 	bn = bitno / BYTESIZ;
256*13305Ssam 	i = bn % DBLKSIZ;
257*13305Ssam 	b = bn / DBLKSIZ;
258*13305Ssam 	if(b != oldb) {
259*13305Ssam 		clrbuf(dirbuf, DBLKSIZ);
260*13305Ssam 		lseek(dirf, (long)b*DBLKSIZ, 0);
261*13305Ssam 		read(dirf, dirbuf, DBLKSIZ);
262*13305Ssam 		oldb = b;
263*13305Ssam 	}
264*13305Ssam 	if(dirbuf[i] & (1<<n))
265*13305Ssam 		return(1);
266*13305Ssam 	return(0);
267*13305Ssam }
268*13305Ssam 
269*13305Ssam setbit()
270*13305Ssam {
271*13305Ssam 	long bn;
272*13305Ssam 	register i, n, b;
273*13305Ssam 
274*13305Ssam 	if (dbrdonly)
275*13305Ssam 		return -1;
276*13305Ssam 	if(bitno > maxbno) {
277*13305Ssam 		maxbno = bitno;
278*13305Ssam 		getbit();
279*13305Ssam 	}
280*13305Ssam 	n = bitno % BYTESIZ;
281*13305Ssam 	bn = bitno / BYTESIZ;
282*13305Ssam 	i = bn % DBLKSIZ;
283*13305Ssam 	b = bn / DBLKSIZ;
284*13305Ssam 	dirbuf[i] |= 1<<n;
285*13305Ssam 	lseek(dirf, (long)b*DBLKSIZ, 0);
286*13305Ssam 	write(dirf, dirbuf, DBLKSIZ);
287*13305Ssam }
288*13305Ssam 
289*13305Ssam clrbuf(cp, n)
290*13305Ssam register char *cp;
291*13305Ssam register n;
292*13305Ssam {
293*13305Ssam 
294*13305Ssam 	do
295*13305Ssam 		*cp++ = 0;
296*13305Ssam 	while(--n);
297*13305Ssam }
298*13305Ssam 
299*13305Ssam datum
300*13305Ssam makdatum(buf, n)
301*13305Ssam char buf[PBLKSIZ];
302*13305Ssam {
303*13305Ssam 	register short *sp;
304*13305Ssam 	register t;
305*13305Ssam 	datum item;
306*13305Ssam 
307*13305Ssam 	sp = (short *)buf;
308*13305Ssam 	if(n < 0 || n >= sp[0])
309*13305Ssam 		goto null;
310*13305Ssam 	t = PBLKSIZ;
311*13305Ssam 	if(n > 0)
312*13305Ssam 		t = sp[n+1-1];
313*13305Ssam 	item.dptr = buf+sp[n+1];
314*13305Ssam 	item.dsize = t - sp[n+1];
315*13305Ssam 	return(item);
316*13305Ssam 
317*13305Ssam null:
318*13305Ssam 	item.dptr = NULL;
319*13305Ssam 	item.dsize = 0;
320*13305Ssam 	return(item);
321*13305Ssam }
322*13305Ssam 
323*13305Ssam cmpdatum(d1, d2)
324*13305Ssam datum d1, d2;
325*13305Ssam {
326*13305Ssam 	register n;
327*13305Ssam 	register char *p1, *p2;
328*13305Ssam 
329*13305Ssam 	n = d1.dsize;
330*13305Ssam 	if(n != d2.dsize)
331*13305Ssam 		return(n - d2.dsize);
332*13305Ssam 	if(n == 0)
333*13305Ssam 		return(0);
334*13305Ssam 	p1 = d1.dptr;
335*13305Ssam 	p2 = d2.dptr;
336*13305Ssam 	do
337*13305Ssam 		if(*p1++ != *p2++)
338*13305Ssam 			return(*--p1 - *--p2);
339*13305Ssam 	while(--n);
340*13305Ssam 	return(0);
341*13305Ssam }
342*13305Ssam 
343*13305Ssam int	hitab[16]
344*13305Ssam /* ken's
345*13305Ssam {
346*13305Ssam 	055,043,036,054,063,014,004,005,
347*13305Ssam 	010,064,077,000,035,027,025,071,
348*13305Ssam };
349*13305Ssam */
350*13305Ssam  = {	61, 57, 53, 49, 45, 41, 37, 33,
351*13305Ssam 	29, 25, 21, 17, 13,  9,  5,  1,
352*13305Ssam };
353*13305Ssam long	hltab[64]
354*13305Ssam  = {
355*13305Ssam 	06100151277L,06106161736L,06452611562L,05001724107L,
356*13305Ssam 	02614772546L,04120731531L,04665262210L,07347467531L,
357*13305Ssam 	06735253126L,06042345173L,03072226605L,01464164730L,
358*13305Ssam 	03247435524L,07652510057L,01546775256L,05714532133L,
359*13305Ssam 	06173260402L,07517101630L,02431460343L,01743245566L,
360*13305Ssam 	00261675137L,02433103631L,03421772437L,04447707466L,
361*13305Ssam 	04435620103L,03757017115L,03641531772L,06767633246L,
362*13305Ssam 	02673230344L,00260612216L,04133454451L,00615531516L,
363*13305Ssam 	06137717526L,02574116560L,02304023373L,07061702261L,
364*13305Ssam 	05153031405L,05322056705L,07401116734L,06552375715L,
365*13305Ssam 	06165233473L,05311063631L,01212221723L,01052267235L,
366*13305Ssam 	06000615237L,01075222665L,06330216006L,04402355630L,
367*13305Ssam 	01451177262L,02000133436L,06025467062L,07121076461L,
368*13305Ssam 	03123433522L,01010635225L,01716177066L,05161746527L,
369*13305Ssam 	01736635071L,06243505026L,03637211610L,01756474365L,
370*13305Ssam 	04723077174L,03642763134L,05750130273L,03655541561L,
371*13305Ssam };
372*13305Ssam 
373*13305Ssam long
374*13305Ssam hashinc(hash)
375*13305Ssam long hash;
376*13305Ssam {
377*13305Ssam 	long bit;
378*13305Ssam 
379*13305Ssam 	hash &= hmask;
380*13305Ssam 	bit = hmask+1;
381*13305Ssam 	for(;;) {
382*13305Ssam 		bit >>= 1;
383*13305Ssam 		if(bit == 0)
384*13305Ssam 			return(0L);
385*13305Ssam 		if((hash&bit) == 0)
386*13305Ssam 			return(hash|bit);
387*13305Ssam 		hash &= ~bit;
388*13305Ssam 	}
389*13305Ssam }
390*13305Ssam 
391*13305Ssam long
392*13305Ssam calchash(item)
393*13305Ssam datum item;
394*13305Ssam {
395*13305Ssam 	register i, j, f;
396*13305Ssam 	long hashl;
397*13305Ssam 	int hashi;
398*13305Ssam 
399*13305Ssam 	hashl = 0;
400*13305Ssam 	hashi = 0;
401*13305Ssam 	for(i=0; i<item.dsize; i++) {
402*13305Ssam 		f = item.dptr[i];
403*13305Ssam 		for(j=0; j<BYTESIZ; j+=4) {
404*13305Ssam 			hashi += hitab[f&017];
405*13305Ssam 			hashl += hltab[hashi&63];
406*13305Ssam 			f >>= 4;
407*13305Ssam 		}
408*13305Ssam 	}
409*13305Ssam 	return(hashl);
410*13305Ssam }
411*13305Ssam 
412*13305Ssam delitem(buf, n)
413*13305Ssam char buf[PBLKSIZ];
414*13305Ssam {
415*13305Ssam 	register short *sp;
416*13305Ssam 	register i1, i2, i3;
417*13305Ssam 
418*13305Ssam 	sp = (short *)buf;
419*13305Ssam 	if(n < 0 || n >= sp[0])
420*13305Ssam 		goto bad;
421*13305Ssam 	i1 = sp[n+1];
422*13305Ssam 	i2 = PBLKSIZ;
423*13305Ssam 	if(n > 0)
424*13305Ssam 		i2 = sp[n+1-1];
425*13305Ssam 	i3 = sp[sp[0]+1-1];
426*13305Ssam 	if(i2 > i1)
427*13305Ssam 	while(i1 > i3) {
428*13305Ssam 		i1--;
429*13305Ssam 		i2--;
430*13305Ssam 		buf[i2] = buf[i1];
431*13305Ssam 		buf[i1] = 0;
432*13305Ssam 	}
433*13305Ssam 	i2 -= i1;
434*13305Ssam 	for(i1=n+1; i1<sp[0]; i1++)
435*13305Ssam 		sp[i1+1-1] = sp[i1+1] + i2;
436*13305Ssam 	sp[0]--;
437*13305Ssam 	sp[sp[0]+1] = 0;
438*13305Ssam 	return;
439*13305Ssam 
440*13305Ssam bad:
441*13305Ssam 	printf("bad delitem\n");
442*13305Ssam 	abort();
443*13305Ssam }
444*13305Ssam 
445*13305Ssam additem(buf, item)
446*13305Ssam char buf[PBLKSIZ];
447*13305Ssam datum item;
448*13305Ssam {
449*13305Ssam 	register short *sp;
450*13305Ssam 	register i1, i2;
451*13305Ssam 
452*13305Ssam 	sp = (short *)buf;
453*13305Ssam 	i1 = PBLKSIZ;
454*13305Ssam 	if(sp[0] > 0)
455*13305Ssam 		i1 = sp[sp[0]+1-1];
456*13305Ssam 	i1 -= item.dsize;
457*13305Ssam 	i2 = (sp[0]+2) * sizeof(short);
458*13305Ssam 	if(i1 <= i2)
459*13305Ssam 		return(-1);
460*13305Ssam 	sp[sp[0]+1] = i1;
461*13305Ssam 	for(i2=0; i2<item.dsize; i2++) {
462*13305Ssam 		buf[i1] = item.dptr[i2];
463*13305Ssam 		i1++;
464*13305Ssam 	}
465*13305Ssam 	sp[0]++;
466*13305Ssam 	return(sp[0]-1);
467*13305Ssam }
468*13305Ssam 
469*13305Ssam chkblk(buf)
470*13305Ssam char buf[PBLKSIZ];
471*13305Ssam {
472*13305Ssam 	register short *sp;
473*13305Ssam 	register t, i;
474*13305Ssam 
475*13305Ssam 	sp = (short *)buf;
476*13305Ssam 	t = PBLKSIZ;
477*13305Ssam 	for(i=0; i<sp[0]; i++) {
478*13305Ssam 		if(sp[i+1] > t)
479*13305Ssam 			goto bad;
480*13305Ssam 		t = sp[i+1];
481*13305Ssam 	}
482*13305Ssam 	if(t < (sp[0]+1)*sizeof(short))
483*13305Ssam 		goto bad;
484*13305Ssam 	return;
485*13305Ssam 
486*13305Ssam bad:
487*13305Ssam 	printf("bad block\n");
488*13305Ssam 	abort();
489*13305Ssam 	clrbuf(buf, PBLKSIZ);
490*13305Ssam }
491