xref: /csrg-svn/old/libndbm/ndbm.c (revision 15749)
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