📄 ndbm.c
字号:
#if !defined(lint) && defined(SCCSIDS)#endif /* ndef lint */static char sccsid[] = "@(#)ndbm.c 1.1 92/07/30 SMI"; /* from UCB 4.3 6/19/85 *//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <stdio.h>#include <errno.h>#include <ndbm.h>datum dbm_do_nextkey(/*db, key*/);/*add support for batched writing for NIS*/#define _DBM_DEFWRITE 0x4#define _DBM_DIRTY 0x8#define _DBM_DIRDIRTY 0x10#define dbm_dirty(db) ((db)->dbm_flags & _DBM_DIRTY)#define dbm_dirdirty(db) ((db)->dbm_flags & _DBM_DIRDIRTY)#define dbm_defwrite(db) ((db)->dbm_flags & _DBM_DEFWRITE)#define dbm_setdirty(db) (db)->dbm_flags |= _DBM_DIRTY#define dbm_clrdirty(db) (db)->dbm_flags &= ~_DBM_DIRTY#define dbm_setdirdirty(db) (db)->dbm_flags |= _DBM_DIRDIRTY#define dbm_clrdirdirty(db) (db)->dbm_flags &= ~_DBM_DIRDIRTY/*used to make a dbm file all at once instead of incrementally*/dbm_setdefwrite(db) DBM *db;{ db->dbm_flags |= _DBM_DEFWRITE;}dbm_flush(db) DBM *db;{ int ok=0; if (dbm_flushpag(db)<0) ok= -1; if (dbm_flushdir(db)<0) ok= -1; return(ok);}dbm_flushpag(db) DBM *db;{ int ok=0; if (dbm_dirty(db)){ /*must page out the page*/ (void) lseek(db->dbm_pagf, (long)(db->dbm_pagbno*PBLKSIZ), L_SET); if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; ok= -1; } dbm_clrdirty(db); } return(ok);}dbm_flushdir(db) DBM *db;{ int ok=0; if (dbm_dirdirty(db)){ /*must page out the dir*/ (void) lseek(db->dbm_dirf, (long)(db->dbm_dirbno*DBLKSIZ), L_SET); if (write(db->dbm_dirf, db->dbm_dirbuf, DBLKSIZ) != DBLKSIZ) { ok= -1; } dbm_clrdirdirty(db); } return(ok);}#define BYTESIZ 8#undef setbitstatic datum makdatum();static long dcalchash();extern int errno;extern char *malloc();extern long lseek();extern char *strcpy();extern char *strcat();DBM *dbm_open(file, flags, mode) char *file; int flags, mode;{ struct stat statb; register DBM *db; if ((db = (DBM *)malloc(sizeof *db)) == 0) { errno = ENOMEM; return ((DBM *)0); } db->dbm_flags = (flags & 03) == O_RDONLY ? _DBM_RDONLY : 0; if ((flags & 03) == O_WRONLY) flags = (flags & ~03) | O_RDWR; (void) strcpy(db->dbm_pagbuf, file); (void) strcat(db->dbm_pagbuf, ".pag"); db->dbm_pagf = open(db->dbm_pagbuf, flags, mode); if (db->dbm_pagf < 0) goto bad; (void) strcpy(db->dbm_pagbuf, file); (void) strcat(db->dbm_pagbuf, ".dir"); db->dbm_dirf = open(db->dbm_pagbuf, flags, mode); if (db->dbm_dirf < 0) goto bad1; (void) fstat(db->dbm_dirf, &statb); db->dbm_maxbno = statb.st_size*BYTESIZ-1; db->dbm_pagbno = db->dbm_dirbno = -1; return (db);bad1: (void) close(db->dbm_pagf);bad: free((char *)db); return ((DBM *)0);}voiddbm_close(db) DBM *db;{(void) dbm_close_status(db);}/*close with return code*/intdbm_close_status(db) DBM *db;{ int ok; ok=0; if (dbm_flush(db) <0) ok = -1; if (close(db->dbm_dirf)<0) ok= -1; if ( close(db->dbm_pagf)<0) ok= -1; free((char *)db); return(ok);}longdbm_forder(db, key) register DBM *db; datum key;{ long hash; hash = dcalchash(key); for (db->dbm_hmask=0;; db->dbm_hmask=(db->dbm_hmask<<1)+1) { db->dbm_blkno = hash & db->dbm_hmask; db->dbm_bitno = db->dbm_blkno + db->dbm_hmask; if (getbit(db) == 0) break; } return (db->dbm_blkno);}datumdbm_fetch(db, key) register DBM *db; datum key;{ register i; datum item; if (dbm_error(db)) goto err; dbm_access(db, dcalchash(key)); if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { item = makdatum(db->dbm_pagbuf, i+1); if (item.dptr != NULL) return (item); }err: item.dptr = NULL; item.dsize = 0; return (item);}dbm_delete(db, key) register DBM *db; datum key;{ register i; if (dbm_error(db)) return (-1); if (dbm_rdonly(db)) { errno = EPERM; return (-1); } dbm_access(db, dcalchash(key)); if ((i = finddatum(db->dbm_pagbuf, key)) < 0) return (-1); if (!delitem(db->dbm_pagbuf, i)) goto err; db->dbm_pagbno = db->dbm_blkno; if (dbm_defwrite(db)) { dbm_setdirty(db); } else { (void) lseek(db->dbm_pagf, (long)(db->dbm_blkno*PBLKSIZ), L_SET); if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { err: db->dbm_flags |= _DBM_IOERR; return (-1); } } return (0);}dbm_store(db, key, dat, replace) register DBM *db; datum key, dat; int replace;{ register i; datum item, item1; char ovfbuf[PBLKSIZ]; if (dbm_error(db)) return (-1); if (dbm_rdonly(db)) { errno = EPERM; return (-1); }loop: dbm_access(db, dcalchash(key)); if ((i = finddatum(db->dbm_pagbuf, key)) >= 0) { if (!replace) return (1); if (!delitem(db->dbm_pagbuf, i)) { db->dbm_flags |= _DBM_IOERR; return (-1); } } if (!additem(db->dbm_pagbuf, key, dat)) goto split; db->dbm_pagbno = db->dbm_blkno; if (dbm_defwrite(db)) { dbm_setdirty(db); } else { (void) lseek(db->dbm_pagf, (long)(db->dbm_blkno*PBLKSIZ), L_SET); if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; return (-1); } } return (0);split: if (key.dsize+dat.dsize+3*sizeof(short) >= PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; errno = ENOSPC; return (-1); } bzero(ovfbuf, PBLKSIZ); for (i=0;;) { item = makdatum(db->dbm_pagbuf, i); if (item.dptr == NULL) break; if (dcalchash(item) & (db->dbm_hmask+1)) { item1 = makdatum(db->dbm_pagbuf, i+1); if (item1.dptr == NULL) { /*(void) fprintf(stderr, "ndbm: split not paired\n");*/ db->dbm_flags |= _DBM_IOERR; break; } if (!additem(ovfbuf, item, item1) || !delitem(db->dbm_pagbuf, i)) { db->dbm_flags |= _DBM_IOERR; return (-1); } continue; } i += 2; } db->dbm_pagbno = db->dbm_blkno; (void) lseek(db->dbm_pagf, (long)(db->dbm_blkno*PBLKSIZ), L_SET); if (write(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; return (-1); } dbm_clrdirty(db); /*clear dirty*/ (void) lseek(db->dbm_pagf, (long)((db->dbm_blkno+db->dbm_hmask+1)*PBLKSIZ), L_SET); if (write(db->dbm_pagf, ovfbuf, PBLKSIZ) != PBLKSIZ) { db->dbm_flags |= _DBM_IOERR; return (-1); } if (setbit(db) < 0) { db->dbm_flags |= _DBM_IOERR; return (-1); } goto loop;}static longdbm_hashinc(db,hash) DBM *db; long hash;{ long bit; hash &= db->dbm_hmask; bit = db->dbm_hmask+1; for(;;) { bit >>= 1; if(bit == 0) return(0L); if((hash&bit) == 0) return(hash|bit); hash &= ~bit; }}static datum nullkey= {NULL, 0};datumdbm_firsthash(db,hash)register DBM *db;long hash;{ register i,j; datum item, bitem;loop: dbm_access(db, hash); j=0; bitem = makdatum(db->dbm_pagbuf, 0); for(i=2;; i+=2) { item = makdatum(db->dbm_pagbuf, i); if(item.dptr == NULL) break; if(cmpdatum(bitem, item) < 0) { j=i; bitem = item; } } if(bitem.dptr != NULL) { db->dbm_keyptr = j + 2; db->dbm_blkptr = db->dbm_blkno; return(bitem); } hash = dbm_hashinc(db,hash); if(hash == 0) return(item); /*null item*/ goto loop;}datumdbm_firstkey(db) DBM *db;{ db->dbm_blkptr = 0L; db->dbm_keyptr = 0; return (dbm_firsthash(db, 0L));}datumdbm_nextkey(db) DBM *db;{ return (dbm_do_nextkey(db, nullkey));}/*this is used if keyptr-2,blocknum doesn't point to the previousspecific key allowing the fast hash order search --its use indicates user tampering with our state variables,which some evil users might do to search from some specific place.It finds the first key at or after blkptr,keyptr in block seq orderthis requires looking at all sorts of emtpy blocks in many cases*/static datumdbm_slow_nextkey(db) register DBM *db;{ struct stat statb; datum item; if (dbm_error(db) || fstat(db->dbm_pagf, &statb) < 0) goto err; statb.st_size /= PBLKSIZ; for (;;) { if (db->dbm_blkptr != db->dbm_pagbno) { if (dbm_dirty(db)) dbm_flushpag(db); db->dbm_pagbno = db->dbm_blkptr; (void) lseek(db->dbm_pagf, (long)(db->dbm_blkptr*PBLKSIZ), L_SET); if (read(db->dbm_pagf, db->dbm_pagbuf, PBLKSIZ) != PBLKSIZ) bzero(db->dbm_pagbuf, PBLKSIZ);#ifdef DEBUG else if (chkblk(db->dbm_pagbuf) < 0) db->dbm_flags |= _DBM_IOERR;#endif } /*Am I an empty block?*/ if (((short *)db->dbm_pagbuf)[0] != 0) { item = makdatum(db->dbm_pagbuf, db->dbm_keyptr); if (item.dptr != NULL) { db->dbm_keyptr += 2; return (item); } db->dbm_keyptr = 0; } /*go to next sequential block*/ if (++db->dbm_blkptr >= statb.st_size) break; }err: item.dptr = NULL; item.dsize = 0; return (item);}datumdbm_do_nextkey(db, inkey) register DBM *db; datum inkey;{ datum item,bitem; long hash; datum key; int f; register i; register j; register short *sp; register n; register char *p1, *p2; if ( dbm_error(db) ) { item.dptr = NULL; item.dsize = 0; return (item); } /*user has supplied lastkey*/ if(inkey.dptr != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -