1*21348Sdist /* 2*21348Sdist * Copyright (c) 1983 Regents of the University of California. 3*21348Sdist * All rights reserved. The Berkeley software License Agreement 4*21348Sdist * specifies the terms and conditions for redistribution. 5*21348Sdist */ 6*21348Sdist 715646Sralph #ifndef lint 8*21348Sdist static char sccsid[] = "@(#)ndbm.c 5.1 (Berkeley) 05/30/85"; 9*21348Sdist #endif not lint 1015646Sralph 1115646Sralph #include <sys/types.h> 1215646Sralph #include <sys/stat.h> 1315646Sralph #include <sys/file.h> 1417023Sralph #include <stdio.h> 1515646Sralph #include <errno.h> 1615646Sralph #include <ndbm.h> 1715646Sralph 1815646Sralph #define BYTESIZ 8 1915646Sralph 2015646Sralph static datum makdatum(); 2115646Sralph static long hashinc(); 2215646Sralph static long dcalchash(); 2315646Sralph extern int errno; 2415646Sralph 2515646Sralph DBM * 2617023Sralph dbm_open(file, flags, mode) 2715646Sralph char *file; 2815646Sralph int flags, mode; 2915646Sralph { 3015646Sralph struct stat statb; 3115646Sralph register DBM *db; 3215646Sralph 3315646Sralph if ((db = (DBM *)malloc(sizeof *db)) == 0) { 3415646Sralph errno = ENOMEM; 3515646Sralph return ((DBM *)0); 3615646Sralph } 3717023Sralph db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; 3815646Sralph if ((flags & 03) == O_WRONLY) 3915646Sralph flags = (flags & ~03) | O_RDWR; 4017023Sralph strcpy(db->dbm_pagbuf, file); 4117023Sralph strcat(db->dbm_pagbuf, ".pag"); 4217023Sralph db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); 4317023Sralph if (db->dbm_pagf < 0) 4415646Sralph goto bad; 4517023Sralph strcpy(db->dbm_pagbuf, file); 4617023Sralph strcat(db->dbm_pagbuf, ".dir"); 4717023Sralph db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); 4817023Sralph if (db->dbm_dirf < 0) 4915646Sralph goto bad1; 5017023Sralph fstat(db->dbm_dirf, &statb); 5117023Sralph db->dbm_maxbno = statb.st_size*BYTESIZ-1; 5217023Sralph db->dbm_pagbno = db->dbm_dirbno = -1; 5315646Sralph return (db); 5415646Sralph bad1: 5517023Sralph (void) close(db->dbm_pagf); 5615646Sralph bad: 5715646Sralph free((char *)db); 5815646Sralph return ((DBM *)0); 5915646Sralph } 6015646Sralph 6115646Sralph void 6217023Sralph dbm_close(db) 6315646Sralph DBM *db; 6415646Sralph { 6515646Sralph 6617023Sralph (void) close(db->dbm_dirf); 6717023Sralph (void) close(db->dbm_pagf); 6815646Sralph free((char *)db); 6915646Sralph } 7015646Sralph 7115646Sralph long 7217023Sralph dbm_forder(db, key) 7315646Sralph register DBM *db; 7415646Sralph datum key; 7515646Sralph { 7615646Sralph long hash; 7715646Sralph 7815646Sralph hash = dcalchash(key); 7917023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 8017023Sralph db->dbm_blkno = hash & db->dbm_hmask; 8117023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 8215646Sralph if (getbit(db) == 0) 8315646Sralph break; 8415646Sralph } 8517023Sralph return (db->dbm_blkno); 8615646Sralph } 8715646Sralph 8815646Sralph datum 8917023Sralph dbm_fetch(db, key) 9015646Sralph register DBM *db; 9115646Sralph datum key; 9215646Sralph { 9315646Sralph register i; 9415646Sralph datum item; 9515646Sralph 9617023Sralph if (dbm_error(db)) 9717023Sralph goto err; 9815646Sralph dbm_access(db, dcalchash(key)); 9917164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 10017164Sralph item = makdatum(db->dbm_pagbuf, i+1); 10117164Sralph if (item.dptr != NULL) 10215646Sralph return (item); 10315646Sralph } 10417023Sralph err: 10517023Sralph item.dptr = NULL; 10617023Sralph item.dsize = 0; 10717023Sralph return (item); 10815646Sralph } 10915646Sralph 11017023Sralph dbm_delete(db, key) 11115646Sralph register DBM *db; 11215646Sralph datum key; 11315646Sralph { 11415646Sralph register i; 11515646Sralph datum item; 11615646Sralph 11717023Sralph if (dbm_error(db)) 11817023Sralph return (-1); 11917023Sralph if (dbm_rdonly(db)) { 12015646Sralph errno = EPERM; 12115646Sralph return (-1); 12215646Sralph } 12315646Sralph dbm_access(db, dcalchash(key)); 12417164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) < 0) 12517023Sralph return (-1); 12617164Sralph if (!delitem(db->dbm_pagbuf, i)) 12717164Sralph goto err; 12817023Sralph db->dbm_pagbno = db->dbm_blkno; 12917023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 13017023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 13117164Sralph err: 13217023Sralph db->dbm_flags |= _DBM_IOERR; 13317023Sralph return (-1); 13417023Sralph } 13515646Sralph return (0); 13615646Sralph } 13715646Sralph 13817023Sralph dbm_store(db, key, dat, replace) 13915646Sralph register DBM *db; 14015646Sralph datum key, dat; 14115749Sralph int replace; 14215646Sralph { 14315646Sralph register i; 14417164Sralph datum item, item1; 14515646Sralph char ovfbuf[PBLKSIZ]; 14615646Sralph 14717023Sralph if (dbm_error(db)) 14817023Sralph return (-1); 14917023Sralph if (dbm_rdonly(db)) { 15015646Sralph errno = EPERM; 15115646Sralph return (-1); 15215646Sralph } 15315646Sralph loop: 15415646Sralph dbm_access(db, dcalchash(key)); 15517164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 15617164Sralph if (!replace) 15717164Sralph return (1); 15817164Sralph if (!delitem(db->dbm_pagbuf, i)) { 15917164Sralph db->dbm_flags |= _DBM_IOERR; 16017164Sralph return (-1); 16115646Sralph } 16215646Sralph } 16317164Sralph if (!additem(db->dbm_pagbuf, key, dat)) 16415646Sralph goto split; 16517023Sralph db->dbm_pagbno = db->dbm_blkno; 16617023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 16717023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 16817023Sralph db->dbm_flags |= _DBM_IOERR; 16917023Sralph return (-1); 17017023Sralph } 17115646Sralph return (0); 17215646Sralph 17315646Sralph split: 17417164Sralph if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { 17517023Sralph db->dbm_flags |= _DBM_IOERR; 17615646Sralph errno = ENOSPC; 17715646Sralph return (-1); 17815646Sralph } 17915646Sralph bzero(ovfbuf, PBLKSIZ); 18015646Sralph for (i=0;;) { 18117023Sralph item = makdatum(db->dbm_pagbuf, i); 18215646Sralph if (item.dptr == NULL) 18315646Sralph break; 18417023Sralph if (dcalchash(item) & (db->dbm_hmask+1)) { 18517164Sralph item1 = makdatum(db->dbm_pagbuf, i+1); 18617164Sralph if (item1.dptr == NULL) { 18717023Sralph fprintf(stderr, "ndbm: split not paired\n"); 18817023Sralph db->dbm_flags |= _DBM_IOERR; 18915646Sralph break; 19015646Sralph } 19117164Sralph if (!additem(ovfbuf, item, item1) || 19217023Sralph !delitem(db->dbm_pagbuf, i)) { 19317023Sralph db->dbm_flags |= _DBM_IOERR; 19417023Sralph return (-1); 19517023Sralph } 19615646Sralph continue; 19715646Sralph } 19815646Sralph i += 2; 19915646Sralph } 20017023Sralph db->dbm_pagbno = db->dbm_blkno; 20117023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 20217023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 20317023Sralph db->dbm_flags |= _DBM_IOERR; 20417023Sralph return (-1); 20517023Sralph } 20617023Sralph (void) lseek(db->dbm_pagf, (db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ, L_SET); 20717023Sralph if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { 20817023Sralph db->dbm_flags |= _DBM_IOERR; 20917023Sralph return (-1); 21017023Sralph } 21115646Sralph setbit(db); 21215646Sralph goto loop; 21315646Sralph } 21415646Sralph 21515646Sralph datum 21617023Sralph dbm_firstkey(db) 21715646Sralph DBM *db; 21815646Sralph { 21915646Sralph 22017164Sralph db->dbm_blkptr = 0L; 22117164Sralph db->dbm_keyptr = 0; 22217164Sralph return (dbm_nextkey(db)); 22315646Sralph } 22415646Sralph 22515646Sralph datum 22617164Sralph dbm_nextkey(db) 22715646Sralph register DBM *db; 22815646Sralph { 22917164Sralph struct stat statb; 23017164Sralph datum item; 23115646Sralph 23217164Sralph if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) 23317023Sralph goto err; 23417164Sralph statb.st_size /= PBLKSIZ; 23517164Sralph for (;;) { 23617164Sralph if (db->dbm_blkptr != db->dbm_pagbno) { 23717164Sralph db->dbm_pagbno = db->dbm_blkptr; 23817164Sralph (void) lseek(db->dbm_pagf, db->dbm_blkptr*PBLKSIZ, L_SET); 23917164Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 24017164Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 24117164Sralph #ifdef DEBUG 24217164Sralph else if (chkblk(db->dbm_pagbuf) < 0) 24317164Sralph db->dbm_flags |= _DBM_IOERR; 24417164Sralph #endif 24517164Sralph } 24617164Sralph if (((short *)db->dbm_pagbuf)[0] != 0) { 24717164Sralph item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); 24817164Sralph if (item.dptr != NULL) { 24917164Sralph db->dbm_keyptr += 2; 25017164Sralph return (item); 25117164Sralph } 25217164Sralph db->dbm_keyptr = 0; 25317164Sralph } 25417164Sralph if (++db->dbm_blkptr >= statb.st_size) 25515646Sralph break; 25615646Sralph } 25717023Sralph err: 25817023Sralph item.dptr = NULL; 25917023Sralph item.dsize = 0; 26017023Sralph return (item); 26115646Sralph } 26215646Sralph 26315646Sralph static 26415646Sralph dbm_access(db, hash) 26515646Sralph register DBM *db; 26615646Sralph long hash; 26715646Sralph { 26817164Sralph 26917023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 27017023Sralph db->dbm_blkno = hash & db->dbm_hmask; 27117023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 27215646Sralph if (getbit(db) == 0) 27315646Sralph break; 27415646Sralph } 27517023Sralph if (db->dbm_blkno != db->dbm_pagbno) { 27617023Sralph db->dbm_pagbno = db->dbm_blkno; 27717023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 27817023Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 27917023Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 28017164Sralph #ifdef DEBUG 28117023Sralph else if (chkblk(db->dbm_pagbuf) < 0) 28217023Sralph db->dbm_flags |= _DBM_IOERR; 28317164Sralph #endif 28415646Sralph } 28515646Sralph } 28615646Sralph 28715646Sralph static 28815646Sralph getbit(db) 28915646Sralph register DBM *db; 29015646Sralph { 29115646Sralph long bn; 29215646Sralph register b, i, n; 29315646Sralph 29415646Sralph 29517023Sralph if (db->dbm_bitno > db->dbm_maxbno) 29615646Sralph return (0); 29717023Sralph n = db->dbm_bitno % BYTESIZ; 29817023Sralph bn = db->dbm_bitno / BYTESIZ; 29915646Sralph i = bn % DBLKSIZ; 30015646Sralph b = bn / DBLKSIZ; 30117023Sralph if (b != db->dbm_dirbno) { 30217023Sralph db->dbm_dirbno = b; 30317023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 30417023Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 30517023Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 30615646Sralph } 30717164Sralph return (db->dbm_dirbuf[i] & (1<<n)); 30815646Sralph } 30915646Sralph 31015646Sralph static 31115646Sralph setbit(db) 31215646Sralph register DBM *db; 31315646Sralph { 31415646Sralph long bn; 31515646Sralph register i, n, b; 31615646Sralph 31717164Sralph if (db->dbm_bitno > db->dbm_maxbno) 31817023Sralph db->dbm_maxbno = db->dbm_bitno; 31917023Sralph n = db->dbm_bitno % BYTESIZ; 32017023Sralph bn = db->dbm_bitno / BYTESIZ; 32115646Sralph i = bn % DBLKSIZ; 32215646Sralph b = bn / DBLKSIZ; 32317164Sralph if (b != db->dbm_dirbno) { 32417164Sralph db->dbm_dirbno = b; 32517164Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 32617164Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 32717164Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 32817164Sralph } 32917023Sralph db->dbm_dirbuf[i] |= 1<<n; 33017023Sralph db->dbm_dirbno = b; 33117023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 33217164Sralph if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 33317023Sralph db->dbm_flags |= _DBM_IOERR; 33415646Sralph } 33515646Sralph 33615646Sralph static datum 33715646Sralph makdatum(buf, n) 33815646Sralph char buf[PBLKSIZ]; 33915646Sralph { 34015646Sralph register short *sp; 34115646Sralph register t; 34215646Sralph datum item; 34315646Sralph 34415646Sralph sp = (short *)buf; 34517164Sralph if ((unsigned)n >= sp[0]) { 34617023Sralph item.dptr = NULL; 34717023Sralph item.dsize = 0; 34817023Sralph return (item); 34917023Sralph } 35015646Sralph t = PBLKSIZ; 35115646Sralph if (n > 0) 35217023Sralph t = sp[n]; 35315646Sralph item.dptr = buf+sp[n+1]; 35415646Sralph item.dsize = t - sp[n+1]; 35515646Sralph return (item); 35615646Sralph } 35715646Sralph 35815646Sralph static 35917164Sralph finddatum(buf, item) 36017164Sralph char buf[PBLKSIZ]; 36117164Sralph datum item; 36215646Sralph { 36317164Sralph register short *sp; 36417164Sralph register int i, n, j; 36515646Sralph 36617164Sralph sp = (short *)buf; 36717164Sralph n = PBLKSIZ; 36817164Sralph for (i=0, j=sp[0]; i<j; i+=2, n = sp[i]) { 36917164Sralph n -= sp[i+1]; 37017164Sralph if (n != item.dsize) 37117164Sralph continue; 37217164Sralph if (n == 0 || bcmp(&buf[sp[i+1]], item.dptr, n) == 0) 37317164Sralph return (i); 37417164Sralph } 37517164Sralph return (-1); 37615646Sralph } 37715646Sralph 37815646Sralph static int hitab[16] 37915646Sralph /* ken's 38015646Sralph { 38115646Sralph 055,043,036,054,063,014,004,005, 38215646Sralph 010,064,077,000,035,027,025,071, 38315646Sralph }; 38415646Sralph */ 38515646Sralph = { 61, 57, 53, 49, 45, 41, 37, 33, 38615646Sralph 29, 25, 21, 17, 13, 9, 5, 1, 38715646Sralph }; 38815646Sralph static long hltab[64] 38915646Sralph = { 39015646Sralph 06100151277L,06106161736L,06452611562L,05001724107L, 39115646Sralph 02614772546L,04120731531L,04665262210L,07347467531L, 39215646Sralph 06735253126L,06042345173L,03072226605L,01464164730L, 39315646Sralph 03247435524L,07652510057L,01546775256L,05714532133L, 39415646Sralph 06173260402L,07517101630L,02431460343L,01743245566L, 39515646Sralph 00261675137L,02433103631L,03421772437L,04447707466L, 39615646Sralph 04435620103L,03757017115L,03641531772L,06767633246L, 39715646Sralph 02673230344L,00260612216L,04133454451L,00615531516L, 39815646Sralph 06137717526L,02574116560L,02304023373L,07061702261L, 39915646Sralph 05153031405L,05322056705L,07401116734L,06552375715L, 40015646Sralph 06165233473L,05311063631L,01212221723L,01052267235L, 40115646Sralph 06000615237L,01075222665L,06330216006L,04402355630L, 40215646Sralph 01451177262L,02000133436L,06025467062L,07121076461L, 40315646Sralph 03123433522L,01010635225L,01716177066L,05161746527L, 40415646Sralph 01736635071L,06243505026L,03637211610L,01756474365L, 40515646Sralph 04723077174L,03642763134L,05750130273L,03655541561L, 40615646Sralph }; 40715646Sralph 40815646Sralph static long 40915646Sralph hashinc(db, hash) 41015646Sralph register DBM *db; 41115646Sralph long hash; 41215646Sralph { 41315646Sralph long bit; 41415646Sralph 41517023Sralph hash &= db->dbm_hmask; 41617023Sralph bit = db->dbm_hmask+1; 41715646Sralph for (;;) { 41815646Sralph bit >>= 1; 41915646Sralph if (bit == 0) 42015646Sralph return (0L); 42117023Sralph if ((hash & bit) == 0) 42217023Sralph return (hash | bit); 42315646Sralph hash &= ~bit; 42415646Sralph } 42515646Sralph } 42615646Sralph 42715646Sralph static long 42815646Sralph dcalchash(item) 42915646Sralph datum item; 43015646Sralph { 43117023Sralph register int s, c, j; 43217023Sralph register char *cp; 43317023Sralph register long hashl; 43417023Sralph register int hashi; 43515646Sralph 43615646Sralph hashl = 0; 43715646Sralph hashi = 0; 43817023Sralph for (cp = item.dptr, s=item.dsize; --s >= 0; ) { 43917023Sralph c = *cp++; 44015646Sralph for (j=0; j<BYTESIZ; j+=4) { 44117023Sralph hashi += hitab[c&017]; 44215646Sralph hashl += hltab[hashi&63]; 44317023Sralph c >>= 4; 44415646Sralph } 44515646Sralph } 44615646Sralph return (hashl); 44715646Sralph } 44815646Sralph 44917164Sralph /* 45017164Sralph * Delete pairs of items (n & n+1). 45117164Sralph */ 45215646Sralph static 45315646Sralph delitem(buf, n) 45415646Sralph char buf[PBLKSIZ]; 45515646Sralph { 45617023Sralph register short *sp, *sp1; 45717023Sralph register i1, i2; 45815646Sralph 45915646Sralph sp = (short *)buf; 46017023Sralph i2 = sp[0]; 46117164Sralph if ((unsigned)n >= i2 || (n & 1)) 46217023Sralph return (0); 46317164Sralph if (n == i2-2) { 46417164Sralph sp[0] -= 2; 46517023Sralph return (1); 46617023Sralph } 46717023Sralph i1 = PBLKSIZ; 46815646Sralph if (n > 0) 46917023Sralph i1 = sp[n]; 47017164Sralph i1 -= sp[n+2]; 47117023Sralph if (i1 > 0) { 47217023Sralph i2 = sp[i2]; 47317164Sralph bcopy(&buf[i2], &buf[i2 + i1], sp[n+2] - i2); 47415646Sralph } 47517164Sralph sp[0] -= 2; 47617164Sralph for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) 47717164Sralph sp[0] = sp[2] + i1; 47817023Sralph return (1); 47915646Sralph } 48015646Sralph 48117164Sralph /* 48217164Sralph * Add pairs of items (item & item1). 48317164Sralph */ 48415646Sralph static 48517164Sralph additem(buf, item, item1) 48615646Sralph char buf[PBLKSIZ]; 48717164Sralph datum item, item1; 48815646Sralph { 48915646Sralph register short *sp; 49015646Sralph register i1, i2; 49115646Sralph 49215646Sralph sp = (short *)buf; 49315646Sralph i1 = PBLKSIZ; 49417023Sralph i2 = sp[0]; 49517023Sralph if (i2 > 0) 49617023Sralph i1 = sp[i2]; 49717164Sralph i1 -= item.dsize + item1.dsize; 49817164Sralph if (i1 <= (i2+3) * sizeof(short)) 49917023Sralph return (0); 50017164Sralph sp[0] += 2; 50117164Sralph sp[++i2] = i1 + item1.dsize; 50217164Sralph bcopy(item.dptr, &buf[i1 + item1.dsize], item.dsize); 50317164Sralph sp[++i2] = i1; 50417164Sralph bcopy(item1.dptr, &buf[i1], item1.dsize); 50517023Sralph return (1); 50615646Sralph } 50715646Sralph 50817164Sralph #ifdef DEBUG 50915646Sralph static 51015646Sralph chkblk(buf) 51115646Sralph char buf[PBLKSIZ]; 51215646Sralph { 51315646Sralph register short *sp; 51415646Sralph register t, i; 51515646Sralph 51615646Sralph sp = (short *)buf; 51715646Sralph t = PBLKSIZ; 51815646Sralph for (i=0; i<sp[0]; i++) { 51915646Sralph if (sp[i+1] > t) 52017023Sralph return (-1); 52115646Sralph t = sp[i+1]; 52215646Sralph } 52315646Sralph if (t < (sp[0]+1)*sizeof(short)) 52417023Sralph return (-1); 52517023Sralph return (0); 52615646Sralph } 52717164Sralph #endif 528