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 726571Sdonn #if defined(LIBC_SCCS) && !defined(lint) 8*47255Sbostic static char sccsid[] = "@(#)ndbm.c 5.6 (Berkeley) 03/12/91"; 926571Sdonn #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> 1646497Sbostic #include "ndbm.h" 1715646Sralph 1815646Sralph #define BYTESIZ 8 1923568Smckusick #undef setbit 2015646Sralph 21*47255Sbostic static datum makdatum(); 22*47255Sbostic static long hashinc(); 23*47255Sbostic static long dcalchash(); 24*47255Sbostic static int additem(), delitem(), finddatum(), getbit(); 25*47255Sbostic static void dbm_access(), setbit(); 26*47255Sbostic extern int errno; 2715646Sralph 2815646Sralph DBM * 2917023Sralph dbm_open(file, flags, mode) 30*47255Sbostic const char *file; 3115646Sralph int flags, mode; 3215646Sralph { 3315646Sralph struct stat statb; 3415646Sralph register DBM *db; 3515646Sralph 3615646Sralph if ((db = (DBM *)malloc(sizeof *db)) == 0) { 3715646Sralph errno = ENOMEM; 3815646Sralph return ((DBM *)0); 3915646Sralph } 4017023Sralph db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; 4115646Sralph if ((flags & 03) == O_WRONLY) 4215646Sralph flags = (flags & ~03) | O_RDWR; 4317023Sralph strcpy(db->dbm_pagbuf, file); 4417023Sralph strcat(db->dbm_pagbuf, ".pag"); 4517023Sralph db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); 4617023Sralph if (db->dbm_pagf < 0) 4715646Sralph goto bad; 4817023Sralph strcpy(db->dbm_pagbuf, file); 4917023Sralph strcat(db->dbm_pagbuf, ".dir"); 5017023Sralph db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); 5117023Sralph if (db->dbm_dirf < 0) 5215646Sralph goto bad1; 5317023Sralph fstat(db->dbm_dirf, &statb); 5417023Sralph db->dbm_maxbno = statb.st_size*BYTESIZ-1; 5517023Sralph db->dbm_pagbno = db->dbm_dirbno = -1; 5615646Sralph return (db); 5715646Sralph bad1: 5817023Sralph (void) close(db->dbm_pagf); 5915646Sralph bad: 6015646Sralph free((char *)db); 6115646Sralph return ((DBM *)0); 6215646Sralph } 6315646Sralph 6415646Sralph void 6517023Sralph dbm_close(db) 6615646Sralph DBM *db; 6715646Sralph { 6815646Sralph 6917023Sralph (void) close(db->dbm_dirf); 7017023Sralph (void) close(db->dbm_pagf); 7115646Sralph free((char *)db); 7215646Sralph } 7315646Sralph 7415646Sralph long 7517023Sralph dbm_forder(db, key) 7615646Sralph register DBM *db; 7715646Sralph datum key; 7815646Sralph { 7915646Sralph long hash; 8015646Sralph 8115646Sralph hash = dcalchash(key); 8217023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 8317023Sralph db->dbm_blkno = hash & db->dbm_hmask; 8417023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 8515646Sralph if (getbit(db) == 0) 8615646Sralph break; 8715646Sralph } 8817023Sralph return (db->dbm_blkno); 8915646Sralph } 9015646Sralph 9115646Sralph datum 9217023Sralph dbm_fetch(db, key) 9315646Sralph register DBM *db; 9415646Sralph datum key; 9515646Sralph { 9615646Sralph register i; 9715646Sralph datum item; 9815646Sralph 9917023Sralph if (dbm_error(db)) 10017023Sralph goto err; 10115646Sralph dbm_access(db, dcalchash(key)); 10217164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 10317164Sralph item = makdatum(db->dbm_pagbuf, i+1); 10417164Sralph if (item.dptr != NULL) 10515646Sralph return (item); 10615646Sralph } 10717023Sralph err: 10817023Sralph item.dptr = NULL; 10917023Sralph item.dsize = 0; 11017023Sralph return (item); 11115646Sralph } 11215646Sralph 11317023Sralph dbm_delete(db, key) 11415646Sralph register DBM *db; 11515646Sralph datum key; 11615646Sralph { 11715646Sralph register i; 11815646Sralph datum item; 11915646Sralph 12017023Sralph if (dbm_error(db)) 12117023Sralph return (-1); 12217023Sralph if (dbm_rdonly(db)) { 12315646Sralph errno = EPERM; 12415646Sralph return (-1); 12515646Sralph } 12615646Sralph dbm_access(db, dcalchash(key)); 12717164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) < 0) 12817023Sralph return (-1); 12917164Sralph if (!delitem(db->dbm_pagbuf, i)) 13017164Sralph goto err; 13117023Sralph db->dbm_pagbno = db->dbm_blkno; 13217023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 13317023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 13417164Sralph err: 13517023Sralph db->dbm_flags |= _DBM_IOERR; 13617023Sralph return (-1); 13717023Sralph } 13815646Sralph return (0); 13915646Sralph } 14015646Sralph 14117023Sralph dbm_store(db, key, dat, replace) 14215646Sralph register DBM *db; 14315646Sralph datum key, dat; 14415749Sralph int replace; 14515646Sralph { 14615646Sralph register i; 14717164Sralph datum item, item1; 14815646Sralph char ovfbuf[PBLKSIZ]; 14915646Sralph 15017023Sralph if (dbm_error(db)) 15117023Sralph return (-1); 15217023Sralph if (dbm_rdonly(db)) { 15315646Sralph errno = EPERM; 15415646Sralph return (-1); 15515646Sralph } 15615646Sralph loop: 15715646Sralph dbm_access(db, dcalchash(key)); 15817164Sralph if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { 15917164Sralph if (!replace) 16017164Sralph return (1); 16117164Sralph if (!delitem(db->dbm_pagbuf, i)) { 16217164Sralph db->dbm_flags |= _DBM_IOERR; 16317164Sralph return (-1); 16415646Sralph } 16515646Sralph } 16617164Sralph if (!additem(db->dbm_pagbuf, key, dat)) 16715646Sralph goto split; 16817023Sralph db->dbm_pagbno = db->dbm_blkno; 16917023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 17017023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 17117023Sralph db->dbm_flags |= _DBM_IOERR; 17217023Sralph return (-1); 17317023Sralph } 17415646Sralph return (0); 17515646Sralph 17615646Sralph split: 17717164Sralph if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { 17817023Sralph db->dbm_flags |= _DBM_IOERR; 17915646Sralph errno = ENOSPC; 18015646Sralph return (-1); 18115646Sralph } 18215646Sralph bzero(ovfbuf, PBLKSIZ); 18315646Sralph for (i=0;;) { 18417023Sralph item = makdatum(db->dbm_pagbuf, i); 18515646Sralph if (item.dptr == NULL) 18615646Sralph break; 18717023Sralph if (dcalchash(item) & (db->dbm_hmask+1)) { 18817164Sralph item1 = makdatum(db->dbm_pagbuf, i+1); 18917164Sralph if (item1.dptr == NULL) { 19017023Sralph fprintf(stderr, "ndbm: split not paired\n"); 19117023Sralph db->dbm_flags |= _DBM_IOERR; 19215646Sralph break; 19315646Sralph } 19417164Sralph if (!additem(ovfbuf, item, item1) || 19517023Sralph !delitem(db->dbm_pagbuf, i)) { 19617023Sralph db->dbm_flags |= _DBM_IOERR; 19717023Sralph return (-1); 19817023Sralph } 19915646Sralph continue; 20015646Sralph } 20115646Sralph i += 2; 20215646Sralph } 20317023Sralph db->dbm_pagbno = db->dbm_blkno; 20417023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 20517023Sralph if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { 20617023Sralph db->dbm_flags |= _DBM_IOERR; 20717023Sralph return (-1); 20817023Sralph } 20917023Sralph (void) lseek(db->dbm_pagf, (db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ, L_SET); 21017023Sralph if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { 21117023Sralph db->dbm_flags |= _DBM_IOERR; 21217023Sralph return (-1); 21317023Sralph } 21415646Sralph setbit(db); 21515646Sralph goto loop; 21615646Sralph } 21715646Sralph 21815646Sralph datum 21917023Sralph dbm_firstkey(db) 22015646Sralph DBM *db; 22115646Sralph { 22215646Sralph 22317164Sralph db->dbm_blkptr = 0L; 22417164Sralph db->dbm_keyptr = 0; 22517164Sralph return (dbm_nextkey(db)); 22615646Sralph } 22715646Sralph 22815646Sralph datum 22917164Sralph dbm_nextkey(db) 23015646Sralph register DBM *db; 23115646Sralph { 23217164Sralph struct stat statb; 23317164Sralph datum item; 23415646Sralph 23517164Sralph if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) 23617023Sralph goto err; 23717164Sralph statb.st_size /= PBLKSIZ; 23817164Sralph for (;;) { 23917164Sralph if (db->dbm_blkptr != db->dbm_pagbno) { 24017164Sralph db->dbm_pagbno = db->dbm_blkptr; 24117164Sralph (void) lseek(db->dbm_pagf, db->dbm_blkptr*PBLKSIZ, L_SET); 24217164Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 24317164Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 24417164Sralph #ifdef DEBUG 24517164Sralph else if (chkblk(db->dbm_pagbuf) < 0) 24617164Sralph db->dbm_flags |= _DBM_IOERR; 24717164Sralph #endif 24817164Sralph } 24917164Sralph if (((short *)db->dbm_pagbuf)[0] != 0) { 25017164Sralph item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); 25117164Sralph if (item.dptr != NULL) { 25217164Sralph db->dbm_keyptr += 2; 25317164Sralph return (item); 25417164Sralph } 25517164Sralph db->dbm_keyptr = 0; 25617164Sralph } 25717164Sralph if (++db->dbm_blkptr >= statb.st_size) 25815646Sralph break; 25915646Sralph } 26017023Sralph err: 26117023Sralph item.dptr = NULL; 26217023Sralph item.dsize = 0; 26317023Sralph return (item); 26415646Sralph } 26515646Sralph 266*47255Sbostic static void 26715646Sralph dbm_access(db, hash) 26815646Sralph register DBM *db; 26915646Sralph long hash; 27015646Sralph { 27117164Sralph 27217023Sralph for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { 27317023Sralph db->dbm_blkno = hash & db->dbm_hmask; 27417023Sralph db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; 27515646Sralph if (getbit(db) == 0) 27615646Sralph break; 27715646Sralph } 27817023Sralph if (db->dbm_blkno != db->dbm_pagbno) { 27917023Sralph db->dbm_pagbno = db->dbm_blkno; 28017023Sralph (void) lseek(db->dbm_pagf, db->dbm_blkno*PBLKSIZ, L_SET); 28117023Sralph if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) 28217023Sralph bzero(db->dbm_pagbuf, PBLKSIZ); 28317164Sralph #ifdef DEBUG 28417023Sralph else if (chkblk(db->dbm_pagbuf) < 0) 28517023Sralph db->dbm_flags |= _DBM_IOERR; 28617164Sralph #endif 28715646Sralph } 28815646Sralph } 28915646Sralph 29015646Sralph static 29115646Sralph getbit(db) 29215646Sralph register DBM *db; 29315646Sralph { 29415646Sralph long bn; 29515646Sralph register b, i, n; 29615646Sralph 29715646Sralph 29817023Sralph if (db->dbm_bitno > db->dbm_maxbno) 29915646Sralph return (0); 30017023Sralph n = db->dbm_bitno % BYTESIZ; 30117023Sralph bn = db->dbm_bitno / BYTESIZ; 30215646Sralph i = bn % DBLKSIZ; 30315646Sralph b = bn / DBLKSIZ; 30417023Sralph if (b != db->dbm_dirbno) { 30517023Sralph db->dbm_dirbno = b; 30617023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 30717023Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 30817023Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 30915646Sralph } 31017164Sralph return (db->dbm_dirbuf[i] & (1<<n)); 31115646Sralph } 31215646Sralph 313*47255Sbostic static void 31415646Sralph setbit(db) 31515646Sralph register DBM *db; 31615646Sralph { 31715646Sralph long bn; 31815646Sralph register i, n, b; 31915646Sralph 32017164Sralph if (db->dbm_bitno > db->dbm_maxbno) 32117023Sralph db->dbm_maxbno = db->dbm_bitno; 32217023Sralph n = db->dbm_bitno % BYTESIZ; 32317023Sralph bn = db->dbm_bitno / BYTESIZ; 32415646Sralph i = bn % DBLKSIZ; 32515646Sralph b = bn / DBLKSIZ; 32617164Sralph if (b != db->dbm_dirbno) { 32717164Sralph db->dbm_dirbno = b; 32817164Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 32917164Sralph if (read(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 33017164Sralph bzero(db->dbm_dirbuf, DBLKSIZ); 33117164Sralph } 33217023Sralph db->dbm_dirbuf[i] |= 1<<n; 33317023Sralph db->dbm_dirbno = b; 33417023Sralph (void) lseek(db->dbm_dirf, (long)b*DBLKSIZ, L_SET); 33517164Sralph if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) 33617023Sralph db->dbm_flags |= _DBM_IOERR; 33715646Sralph } 33815646Sralph 33915646Sralph static datum 34015646Sralph makdatum(buf, n) 34115646Sralph char buf[PBLKSIZ]; 34215646Sralph { 34315646Sralph register short *sp; 34415646Sralph register t; 34515646Sralph datum item; 34615646Sralph 34715646Sralph sp = (short *)buf; 34817164Sralph if ((unsigned)n >= sp[0]) { 34917023Sralph item.dptr = NULL; 35017023Sralph item.dsize = 0; 35117023Sralph return (item); 35217023Sralph } 35315646Sralph t = PBLKSIZ; 35415646Sralph if (n > 0) 35517023Sralph t = sp[n]; 35615646Sralph item.dptr = buf+sp[n+1]; 35715646Sralph item.dsize = t - sp[n+1]; 35815646Sralph return (item); 35915646Sralph } 36015646Sralph 36115646Sralph static 36217164Sralph finddatum(buf, item) 36317164Sralph char buf[PBLKSIZ]; 36417164Sralph datum item; 36515646Sralph { 36617164Sralph register short *sp; 36717164Sralph register int i, n, j; 36815646Sralph 36917164Sralph sp = (short *)buf; 37017164Sralph n = PBLKSIZ; 37117164Sralph for (i=0, j=sp[0]; i<j; i+=2, n = sp[i]) { 37217164Sralph n -= sp[i+1]; 37317164Sralph if (n != item.dsize) 37417164Sralph continue; 37517164Sralph if (n == 0 || bcmp(&buf[sp[i+1]], item.dptr, n) == 0) 37617164Sralph return (i); 37717164Sralph } 37817164Sralph return (-1); 37915646Sralph } 38015646Sralph 38115646Sralph static int hitab[16] 38215646Sralph /* ken's 38315646Sralph { 38415646Sralph 055,043,036,054,063,014,004,005, 38515646Sralph 010,064,077,000,035,027,025,071, 38615646Sralph }; 38715646Sralph */ 38815646Sralph = { 61, 57, 53, 49, 45, 41, 37, 33, 38915646Sralph 29, 25, 21, 17, 13, 9, 5, 1, 39015646Sralph }; 39115646Sralph static long hltab[64] 39215646Sralph = { 39315646Sralph 06100151277L,06106161736L,06452611562L,05001724107L, 39415646Sralph 02614772546L,04120731531L,04665262210L,07347467531L, 39515646Sralph 06735253126L,06042345173L,03072226605L,01464164730L, 39615646Sralph 03247435524L,07652510057L,01546775256L,05714532133L, 39715646Sralph 06173260402L,07517101630L,02431460343L,01743245566L, 39815646Sralph 00261675137L,02433103631L,03421772437L,04447707466L, 39915646Sralph 04435620103L,03757017115L,03641531772L,06767633246L, 40015646Sralph 02673230344L,00260612216L,04133454451L,00615531516L, 40115646Sralph 06137717526L,02574116560L,02304023373L,07061702261L, 40215646Sralph 05153031405L,05322056705L,07401116734L,06552375715L, 40315646Sralph 06165233473L,05311063631L,01212221723L,01052267235L, 40415646Sralph 06000615237L,01075222665L,06330216006L,04402355630L, 40515646Sralph 01451177262L,02000133436L,06025467062L,07121076461L, 40615646Sralph 03123433522L,01010635225L,01716177066L,05161746527L, 40715646Sralph 01736635071L,06243505026L,03637211610L,01756474365L, 40815646Sralph 04723077174L,03642763134L,05750130273L,03655541561L, 40915646Sralph }; 41015646Sralph 41115646Sralph static long 41215646Sralph hashinc(db, hash) 41315646Sralph register DBM *db; 41415646Sralph long hash; 41515646Sralph { 41615646Sralph long bit; 41715646Sralph 41817023Sralph hash &= db->dbm_hmask; 41917023Sralph bit = db->dbm_hmask+1; 42015646Sralph for (;;) { 42115646Sralph bit >>= 1; 42215646Sralph if (bit == 0) 42315646Sralph return (0L); 42417023Sralph if ((hash & bit) == 0) 42517023Sralph return (hash | bit); 42615646Sralph hash &= ~bit; 42715646Sralph } 42815646Sralph } 42915646Sralph 43015646Sralph static long 43115646Sralph dcalchash(item) 43215646Sralph datum item; 43315646Sralph { 43417023Sralph register int s, c, j; 43517023Sralph register char *cp; 43617023Sralph register long hashl; 43717023Sralph register int hashi; 43815646Sralph 43915646Sralph hashl = 0; 44015646Sralph hashi = 0; 44117023Sralph for (cp = item.dptr, s=item.dsize; --s >= 0; ) { 44217023Sralph c = *cp++; 44315646Sralph for (j=0; j<BYTESIZ; j+=4) { 44417023Sralph hashi += hitab[c&017]; 44515646Sralph hashl += hltab[hashi&63]; 44617023Sralph c >>= 4; 44715646Sralph } 44815646Sralph } 44915646Sralph return (hashl); 45015646Sralph } 45115646Sralph 45217164Sralph /* 45317164Sralph * Delete pairs of items (n & n+1). 45417164Sralph */ 45515646Sralph static 45615646Sralph delitem(buf, n) 45715646Sralph char buf[PBLKSIZ]; 45815646Sralph { 45917023Sralph register short *sp, *sp1; 46017023Sralph register i1, i2; 46115646Sralph 46215646Sralph sp = (short *)buf; 46317023Sralph i2 = sp[0]; 46417164Sralph if ((unsigned)n >= i2 || (n & 1)) 46517023Sralph return (0); 46617164Sralph if (n == i2-2) { 46717164Sralph sp[0] -= 2; 46817023Sralph return (1); 46917023Sralph } 47017023Sralph i1 = PBLKSIZ; 47115646Sralph if (n > 0) 47217023Sralph i1 = sp[n]; 47317164Sralph i1 -= sp[n+2]; 47417023Sralph if (i1 > 0) { 47517023Sralph i2 = sp[i2]; 47617164Sralph bcopy(&buf[i2], &buf[i2 + i1], sp[n+2] - i2); 47715646Sralph } 47817164Sralph sp[0] -= 2; 47917164Sralph for (sp1 = sp + sp[0], sp += n+1; sp <= sp1; sp++) 48017164Sralph sp[0] = sp[2] + i1; 48117023Sralph return (1); 48215646Sralph } 48315646Sralph 48417164Sralph /* 48517164Sralph * Add pairs of items (item & item1). 48617164Sralph */ 48715646Sralph static 48817164Sralph additem(buf, item, item1) 48915646Sralph char buf[PBLKSIZ]; 49017164Sralph datum item, item1; 49115646Sralph { 49215646Sralph register short *sp; 49315646Sralph register i1, i2; 49415646Sralph 49515646Sralph sp = (short *)buf; 49615646Sralph i1 = PBLKSIZ; 49717023Sralph i2 = sp[0]; 49817023Sralph if (i2 > 0) 49917023Sralph i1 = sp[i2]; 50017164Sralph i1 -= item.dsize + item1.dsize; 50132107Smckusick if (i1 <= (i2+3) * (int)sizeof(short)) 50217023Sralph return (0); 50317164Sralph sp[0] += 2; 50417164Sralph sp[++i2] = i1 + item1.dsize; 50517164Sralph bcopy(item.dptr, &buf[i1 + item1.dsize], item.dsize); 50617164Sralph sp[++i2] = i1; 50717164Sralph bcopy(item1.dptr, &buf[i1], item1.dsize); 50817023Sralph return (1); 50915646Sralph } 51015646Sralph 51117164Sralph #ifdef DEBUG 51215646Sralph static 51315646Sralph chkblk(buf) 51415646Sralph char buf[PBLKSIZ]; 51515646Sralph { 51615646Sralph register short *sp; 51715646Sralph register t, i; 51815646Sralph 51915646Sralph sp = (short *)buf; 52015646Sralph t = PBLKSIZ; 52115646Sralph for (i=0; i<sp[0]; i++) { 52215646Sralph if (sp[i+1] > t) 52317023Sralph return (-1); 52415646Sralph t = sp[i+1]; 52515646Sralph } 52615646Sralph if (t < (sp[0]+1)*sizeof(short)) 52717023Sralph return (-1); 52817023Sralph return (0); 52915646Sralph } 53017164Sralph #endif 531