121348Sdist /* 221348Sdist * Copyright (c) 1983 Regents of the University of California. 321348Sdist * All rights reserved. The Berkeley software License Agreement 421348Sdist * specifies the terms and conditions for redistribution. 521348Sdist */ 621348Sdist 7*26571Sdonn #if defined(LIBC_SCCS) && !defined(lint) 8*26571Sdonn static char sccsid[] = "@(#)ndbm.c 5.3 (Berkeley) 03/09/86"; 9*26571Sdonn #endif LIBC_SCCS and 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 1923568Smckusick #undef setbit 2015646Sralph 2115646Sralph static datum makdatum(); 2215646Sralph static long hashinc(); 2315646Sralph static long dcalchash(); 2415646Sralph extern int errno; 2515646Sralph 2615646Sralph DBM * 2717023Sralph dbm_open(file, flags, mode) 2815646Sralph char *file; 2915646Sralph int flags, mode; 3015646Sralph { 3115646Sralph struct stat statb; 3215646Sralph register DBM *db; 3315646Sralph 3415646Sralph if ((db = (DBM *)malloc(sizeof *db)) == 0) { 3515646Sralph errno = ENOMEM; 3615646Sralph return ((DBM *)0); 3715646Sralph } 3817023Sralph db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; 3915646Sralph if ((flags & 03) == O_WRONLY) 4015646Sralph flags = (flags & ~03) | O_RDWR; 4117023Sralph strcpy(db->dbm_pagbuf, file); 4217023Sralph strcat(db->dbm_pagbuf, ".pag"); 4317023Sralph db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); 4417023Sralph if (db->dbm_pagf < 0) 4515646Sralph goto bad; 4617023Sralph strcpy(db->dbm_pagbuf, file); 4717023Sralph strcat(db->dbm_pagbuf, ".dir"); 4817023Sralph db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); 4917023Sralph if (db->dbm_dirf < 0) 5015646Sralph goto bad1; 5117023Sralph fstat(db->dbm_dirf, &statb); 5217023Sralph db->dbm_maxbno = statb.st_size*BYTESIZ-1; 5317023Sralph db->dbm_pagbno = db->dbm_dirbno = -1; 5415646Sralph return (db); 5515646Sralph bad1: 5617023Sralph (void) close(db->dbm_pagf); 5715646Sralph bad: 5815646Sralph free((char *)db); 5915646Sralph return ((DBM *)0); 6015646Sralph } 6115646Sralph 6215646Sralph void 6317023Sralph dbm_close(db) 6415646Sralph DBM *db; 6515646Sralph { 6615646Sralph 6717023Sralph (void) close(db->dbm_dirf); 6817023Sralph (void) close(db->dbm_pagf); 6915646Sralph free((char *)db); 7015646Sralph } 7115646Sralph 7215646Sralph long 7317023Sralph dbm_forder(db, key) 7415646Sralph register DBM *db; 7515646Sralph datum key; 7615646Sralph { 7715646Sralph long hash; 7815646Sralph 7915646Sralph hash = dcalchash(key); 8017023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 8117023Sralph db->dbm_blkno = hash & db->dbm_hmask; 8217023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 8315646Sralph if (getbit(db) == 0) 8415646Sralph break; 8515646Sralph } 8617023Sralph return (db->dbm_blkno); 8715646Sralph } 8815646Sralph 8915646Sralph datum 9017023Sralph dbm_fetch(db, key) 9115646Sralph register DBM *db; 9215646Sralph datum key; 9315646Sralph { 9415646Sralph register i; 9515646Sralph datum item; 9615646Sralph 9717023Sralph if (dbm_error(db)) 9817023Sralph goto err; 9915646Sralph dbm_access(db, dcalchash(key)); 10017164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 10117164Sralph item = makdatum(db->dbm_pagbuf, i+1); 10217164Sralph if (item.dptr != NULL) 10315646Sralph return (item); 10415646Sralph } 10517023Sralph err: 10617023Sralph item.dptr = NULL; 10717023Sralph item.dsize = 0; 10817023Sralph return (item); 10915646Sralph } 11015646Sralph 11117023Sralph dbm_delete(db, key) 11215646Sralph register DBM *db; 11315646Sralph datum key; 11415646Sralph { 11515646Sralph register i; 11615646Sralph datum item; 11715646Sralph 11817023Sralph if (dbm_error(db)) 11917023Sralph return (-1); 12017023Sralph if (dbm_rdonly(db)) { 12115646Sralph errno = EPERM; 12215646Sralph return (-1); 12315646Sralph } 12415646Sralph dbm_access(db, dcalchash(key)); 12517164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) < 0) 12617023Sralph return (-1); 12717164Sralph if (!delitem(db->dbm_pagbuf, i)) 12817164Sralph goto err; 12917023Sralph db->dbm_pagbno = db->dbm_blkno; 13017023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 13117023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 13217164Sralph err: 13317023Sralph db->dbm_flags |= _DBM_IOERR; 13417023Sralph return (-1); 13517023Sralph } 13615646Sralph return (0); 13715646Sralph } 13815646Sralph 13917023Sralph dbm_store(db, key, dat, replace) 14015646Sralph register DBM *db; 14115646Sralph datum key, dat; 14215749Sralph int replace; 14315646Sralph { 14415646Sralph register i; 14517164Sralph datum item, item1; 14615646Sralph char ovfbuf[PBLKSIZ]; 14715646Sralph 14817023Sralph if (dbm_error(db)) 14917023Sralph return (-1); 15017023Sralph if (dbm_rdonly(db)) { 15115646Sralph errno = EPERM; 15215646Sralph return (-1); 15315646Sralph } 15415646Sralph loop: 15515646Sralph dbm_access(db, dcalchash(key)); 15617164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 15717164Sralph if (!replace) 15817164Sralph return (1); 15917164Sralph if (!delitem(db->dbm_pagbuf, i)) { 16017164Sralph db->dbm_flags |= _DBM_IOERR; 16117164Sralph return (-1); 16215646Sralph } 16315646Sralph } 16417164Sralph if (!additem(db->dbm_pagbuf, key, dat)) 16515646Sralph goto split; 16617023Sralph db->dbm_pagbno = db->dbm_blkno; 16717023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 16817023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 16917023Sralph db->dbm_flags |= _DBM_IOERR; 17017023Sralph return (-1); 17117023Sralph } 17215646Sralph return (0); 17315646Sralph 17415646Sralph split: 17517164Sralph if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { 17617023Sralph db->dbm_flags |= _DBM_IOERR; 17715646Sralph errno = ENOSPC; 17815646Sralph return (-1); 17915646Sralph } 18015646Sralph bzero(ovfbuf, PBLKSIZ); 18115646Sralph for (i=0;;) { 18217023Sralph item = makdatum(db->dbm_pagbuf, i); 18315646Sralph if (item.dptr == NULL) 18415646Sralph break; 18517023Sralph if (dcalchash(item) & (db->dbm_hmask+1)) { 18617164Sralph item1 = makdatum(db->dbm_pagbuf, i+1); 18717164Sralph if (item1.dptr == NULL) { 18817023Sralph fprintf(stderr, "ndbm: split not paired\n"); 18917023Sralph db->dbm_flags |= _DBM_IOERR; 19015646Sralph break; 19115646Sralph } 19217164Sralph if (!additem(ovfbuf, item, item1) || 19317023Sralph !delitem(db->dbm_pagbuf, i)) { 19417023Sralph db->dbm_flags |= _DBM_IOERR; 19517023Sralph return (-1); 19617023Sralph } 19715646Sralph continue; 19815646Sralph } 19915646Sralph i += 2; 20015646Sralph } 20117023Sralph db->dbm_pagbno = db->dbm_blkno; 20217023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 20317023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 20417023Sralph db->dbm_flags |= _DBM_IOERR; 20517023Sralph return (-1); 20617023Sralph } 20717023Sralph (void) lseek(db->dbm_pagf, (db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ, L_SET); 20817023Sralph if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { 20917023Sralph db->dbm_flags |= _DBM_IOERR; 21017023Sralph return (-1); 21117023Sralph } 21215646Sralph setbit(db); 21315646Sralph goto loop; 21415646Sralph } 21515646Sralph 21615646Sralph datum 21717023Sralph dbm_firstkey(db) 21815646Sralph DBM *db; 21915646Sralph { 22015646Sralph 22117164Sralph db->dbm_blkptr = 0L; 22217164Sralph db->dbm_keyptr = 0; 22317164Sralph return (dbm_nextkey(db)); 22415646Sralph } 22515646Sralph 22615646Sralph datum 22717164Sralph dbm_nextkey(db) 22815646Sralph register DBM *db; 22915646Sralph { 23017164Sralph struct stat statb; 23117164Sralph datum item; 23215646Sralph 23317164Sralph if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) 23417023Sralph goto err; 23517164Sralph statb.st_size /= PBLKSIZ; 23617164Sralph for (;;) { 23717164Sralph if (db->dbm_blkptr != db->dbm_pagbno) { 23817164Sralph db->dbm_pagbno = db->dbm_blkptr; 23917164Sralph (void) lseek(db->dbm_pagf, db->dbm_blkptr*PBLKSIZ, L_SET); 24017164Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 24117164Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 24217164Sralph #ifdef DEBUG 24317164Sralph else if (chkblk(db->dbm_pagbuf) < 0) 24417164Sralph db->dbm_flags |= _DBM_IOERR; 24517164Sralph #endif 24617164Sralph } 24717164Sralph if (((short *)db->dbm_pagbuf)[0] != 0) { 24817164Sralph item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); 24917164Sralph if (item.dptr != NULL) { 25017164Sralph db->dbm_keyptr += 2; 25117164Sralph return (item); 25217164Sralph } 25317164Sralph db->dbm_keyptr = 0; 25417164Sralph } 25517164Sralph if (++db->dbm_blkptr >= statb.st_size) 25615646Sralph break; 25715646Sralph } 25817023Sralph err: 25917023Sralph item.dptr = NULL; 26017023Sralph item.dsize = 0; 26117023Sralph return (item); 26215646Sralph } 26315646Sralph 26415646Sralph static 26515646Sralph dbm_access(db, hash) 26615646Sralph register DBM *db; 26715646Sralph long hash; 26815646Sralph { 26917164Sralph 27017023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 27117023Sralph db->dbm_blkno = hash & db->dbm_hmask; 27217023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 27315646Sralph if (getbit(db) == 0) 27415646Sralph break; 27515646Sralph } 27617023Sralph if (db->dbm_blkno != db->dbm_pagbno) { 27717023Sralph db->dbm_pagbno = db->dbm_blkno; 27817023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 27917023Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 28017023Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 28117164Sralph #ifdef DEBUG 28217023Sralph else if (chkblk(db->dbm_pagbuf) < 0) 28317023Sralph db->dbm_flags |= _DBM_IOERR; 28417164Sralph #endif 28515646Sralph } 28615646Sralph } 28715646Sralph 28815646Sralph static 28915646Sralph getbit(db) 29015646Sralph register DBM *db; 29115646Sralph { 29215646Sralph long bn; 29315646Sralph register b, i, n; 29415646Sralph 29515646Sralph 29617023Sralph if (db->dbm_bitno > db->dbm_maxbno) 29715646Sralph return (0); 29817023Sralph n = db->dbm_bitno % BYTESIZ; 29917023Sralph bn = db->dbm_bitno / BYTESIZ; 30015646Sralph i = bn % DBLKSIZ; 30115646Sralph b = bn / DBLKSIZ; 30217023Sralph if (b != db->dbm_dirbno) { 30317023Sralph db->dbm_dirbno = b; 30417023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 30517023Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 30617023Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 30715646Sralph } 30817164Sralph return (db->dbm_dirbuf[i] & (1<<n)); 30915646Sralph } 31015646Sralph 31115646Sralph static 31215646Sralph setbit(db) 31315646Sralph register DBM *db; 31415646Sralph { 31515646Sralph long bn; 31615646Sralph register i, n, b; 31715646Sralph 31817164Sralph if (db->dbm_bitno > db->dbm_maxbno) 31917023Sralph db->dbm_maxbno = db->dbm_bitno; 32017023Sralph n = db->dbm_bitno % BYTESIZ; 32117023Sralph bn = db->dbm_bitno / BYTESIZ; 32215646Sralph i = bn % DBLKSIZ; 32315646Sralph b = bn / DBLKSIZ; 32417164Sralph if (b != db->dbm_dirbno) { 32517164Sralph db->dbm_dirbno = b; 32617164Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 32717164Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 32817164Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 32917164Sralph } 33017023Sralph db->dbm_dirbuf[i] |= 1<<n; 33117023Sralph db->dbm_dirbno = b; 33217023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 33317164Sralph if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 33417023Sralph db->dbm_flags |= _DBM_IOERR; 33515646Sralph } 33615646Sralph 33715646Sralph static datum 33815646Sralph makdatum(buf, n) 33915646Sralph char buf[PBLKSIZ]; 34015646Sralph { 34115646Sralph register short *sp; 34215646Sralph register t; 34315646Sralph datum item; 34415646Sralph 34515646Sralph sp = (short *)buf; 34617164Sralph if ((unsigned)n >= sp[0]) { 34717023Sralph item.dptr = NULL; 34817023Sralph item.dsize = 0; 34917023Sralph return (item); 35017023Sralph } 35115646Sralph t = PBLKSIZ; 35215646Sralph if (n > 0) 35317023Sralph t = sp[n]; 35415646Sralph item.dptr = buf+sp[n+1]; 35515646Sralph item.dsize = t - sp[n+1]; 35615646Sralph return (item); 35715646Sralph } 35815646Sralph 35915646Sralph static 36017164Sralph finddatum(buf, item) 36117164Sralph char buf[PBLKSIZ]; 36217164Sralph datum item; 36315646Sralph { 36417164Sralph register short *sp; 36517164Sralph register int i, n, j; 36615646Sralph 36717164Sralph sp = (short *)buf; 36817164Sralph n = PBLKSIZ; 36917164Sralph for (i=0, j=sp[0]; i<j; i+=2, n = sp[i]) { 37017164Sralph n -= sp[i+1]; 37117164Sralph if (n != item.dsize) 37217164Sralph continue; 37317164Sralph if (n == 0 || bcmp(&buf[sp[i+1]], item.dptr, n) == 0) 37417164Sralph return (i); 37517164Sralph } 37617164Sralph return (-1); 37715646Sralph } 37815646Sralph 37915646Sralph static int hitab[16] 38015646Sralph /* ken's 38115646Sralph { 38215646Sralph 055,043,036,054,063,014,004,005, 38315646Sralph 010,064,077,000,035,027,025,071, 38415646Sralph }; 38515646Sralph */ 38615646Sralph = { 61, 57, 53, 49, 45, 41, 37, 33, 38715646Sralph 29, 25, 21, 17, 13, 9, 5, 1, 38815646Sralph }; 38915646Sralph static long hltab[64] 39015646Sralph = { 39115646Sralph 06100151277L,06106161736L,06452611562L,05001724107L, 39215646Sralph 02614772546L,04120731531L,04665262210L,07347467531L, 39315646Sralph 06735253126L,06042345173L,03072226605L,01464164730L, 39415646Sralph 03247435524L,07652510057L,01546775256L,05714532133L, 39515646Sralph 06173260402L,07517101630L,02431460343L,01743245566L, 39615646Sralph 00261675137L,02433103631L,03421772437L,04447707466L, 39715646Sralph 04435620103L,03757017115L,03641531772L,06767633246L, 39815646Sralph 02673230344L,00260612216L,04133454451L,00615531516L, 39915646Sralph 06137717526L,02574116560L,02304023373L,07061702261L, 40015646Sralph 05153031405L,05322056705L,07401116734L,06552375715L, 40115646Sralph 06165233473L,05311063631L,01212221723L,01052267235L, 40215646Sralph 06000615237L,01075222665L,06330216006L,04402355630L, 40315646Sralph 01451177262L,02000133436L,06025467062L,07121076461L, 40415646Sralph 03123433522L,01010635225L,01716177066L,05161746527L, 40515646Sralph 01736635071L,06243505026L,03637211610L,01756474365L, 40615646Sralph 04723077174L,03642763134L,05750130273L,03655541561L, 40715646Sralph }; 40815646Sralph 40915646Sralph static long 41015646Sralph hashinc(db, hash) 41115646Sralph register DBM *db; 41215646Sralph long hash; 41315646Sralph { 41415646Sralph long bit; 41515646Sralph 41617023Sralph hash &= db->dbm_hmask; 41717023Sralph bit = db->dbm_hmask+1; 41815646Sralph for (;;) { 41915646Sralph bit >>= 1; 42015646Sralph if (bit == 0) 42115646Sralph return (0L); 42217023Sralph if ((hash & bit) == 0) 42317023Sralph return (hash | bit); 42415646Sralph hash &= ~bit; 42515646Sralph } 42615646Sralph } 42715646Sralph 42815646Sralph static long 42915646Sralph dcalchash(item) 43015646Sralph datum item; 43115646Sralph { 43217023Sralph register int s, c, j; 43317023Sralph register char *cp; 43417023Sralph register long hashl; 43517023Sralph register int hashi; 43615646Sralph 43715646Sralph hashl = 0; 43815646Sralph hashi = 0; 43917023Sralph for (cp = item.dptr, s=item.dsize; --s >= 0; ) { 44017023Sralph c = *cp++; 44115646Sralph for (j=0; j<BYTESIZ; j+=4) { 44217023Sralph hashi += hitab[c&017]; 44315646Sralph hashl += hltab[hashi&63]; 44417023Sralph c >>= 4; 44515646Sralph } 44615646Sralph } 44715646Sralph return (hashl); 44815646Sralph } 44915646Sralph 45017164Sralph /* 45117164Sralph * Delete pairs of items (n & n+1). 45217164Sralph */ 45315646Sralph static 45415646Sralph delitem(buf, n) 45515646Sralph char buf[PBLKSIZ]; 45615646Sralph { 45717023Sralph register short *sp, *sp1; 45817023Sralph register i1, i2; 45915646Sralph 46015646Sralph sp = (short *)buf; 46117023Sralph i2 = sp[0]; 46217164Sralph if ((unsigned)n >= i2 || (n & 1)) 46317023Sralph return (0); 46417164Sralph if (n == i2-2) { 46517164Sralph sp[0] -= 2; 46617023Sralph return (1); 46717023Sralph } 46817023Sralph i1 = PBLKSIZ; 46915646Sralph if (n > 0) 47017023Sralph i1 = sp[n]; 47117164Sralph i1 -= sp[n+2]; 47217023Sralph if (i1 > 0) { 47317023Sralph i2 = sp[i2]; 47417164Sralph bcopy(&buf[i2], &buf[i2 + i1], sp[n+2] - i2); 47515646Sralph } 47617164Sralph sp[0] -= 2; 47717164Sralph for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) 47817164Sralph sp[0] = sp[2] + i1; 47917023Sralph return (1); 48015646Sralph } 48115646Sralph 48217164Sralph /* 48317164Sralph * Add pairs of items (item & item1). 48417164Sralph */ 48515646Sralph static 48617164Sralph additem(buf, item, item1) 48715646Sralph char buf[PBLKSIZ]; 48817164Sralph datum item, item1; 48915646Sralph { 49015646Sralph register short *sp; 49115646Sralph register i1, i2; 49215646Sralph 49315646Sralph sp = (short *)buf; 49415646Sralph i1 = PBLKSIZ; 49517023Sralph i2 = sp[0]; 49617023Sralph if (i2 > 0) 49717023Sralph i1 = sp[i2]; 49817164Sralph i1 -= item.dsize + item1.dsize; 49917164Sralph if (i1 <= (i2+3) * sizeof(short)) 50017023Sralph return (0); 50117164Sralph sp[0] += 2; 50217164Sralph sp[++i2] = i1 + item1.dsize; 50317164Sralph bcopy(item.dptr, &buf[i1 + item1.dsize], item.dsize); 50417164Sralph sp[++i2] = i1; 50517164Sralph bcopy(item1.dptr, &buf[i1], item1.dsize); 50617023Sralph return (1); 50715646Sralph } 50815646Sralph 50917164Sralph #ifdef DEBUG 51015646Sralph static 51115646Sralph chkblk(buf) 51215646Sralph char buf[PBLKSIZ]; 51315646Sralph { 51415646Sralph register short *sp; 51515646Sralph register t, i; 51615646Sralph 51715646Sralph sp = (short *)buf; 51815646Sralph t = PBLKSIZ; 51915646Sralph for (i=0; i<sp[0]; i++) { 52015646Sralph if (sp[i+1] > t) 52117023Sralph return (-1); 52215646Sralph t = sp[i+1]; 52315646Sralph } 52415646Sralph if (t < (sp[0]+1)*sizeof(short)) 52517023Sralph return (-1); 52617023Sralph return (0); 52715646Sralph } 52817164Sralph #endif 529