⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bufffile.c

📁 b tree how to operate on b tr
💻 C
📖 第 1 页 / 共 2 页
字号:
/*JS***********************************************************************    Program : BUFFFILE*    Language: ANSI-C + POSIX functions where available*    Author  : Joerg Schoen*    Purpose : Package to provide buffered access to arbitrary regions of*              a file. The interface consists of the following routines:**     bFileOpen, bFileClose:*       Opens and closes the file for buffered access using a handle of*       type BuffFile. Additionally the user may specify to use memory*       mapped I/O for efficiency or that the file should be locked for*       exclusive read/write.*     bFileFlush:*       Ensures that all dirty pages are written to disk.**     bFileGet:*       Gets a pointer to the specified region of the file. The returned*       length may be smaller than the requested one if the region crosses a*       page boundary. In that case multiple calls to bFileGet are necessary.*       Writing is done by marking a buffer 'dirty'.*     bFileSet:*       Used to unprotect a region or to mark it dirty. This routine does*       *not* load the pages, thus it works only after a single bFileGet for*       the region or multiple bFileGet's that lock the region (to ensure*       none of the buffers are reused).**     bFileRead, bFileWrite, bFileByteSet,bFileByteCopy,bFileByteMove:*       Reads and writes data, set and copys regions using multiple calls*       to bFileGet.**************************************************************************/#ifndef lintstatic const char rcsid[] = "$Id: bufffile.c,v 1.12 1998/02/26 17:50:45 joerg Stab joerg $";#endif/*********     INCLUDES                                         *********/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <jsconfig.h>#include <jssubs.h>#ifndef CONFIG_NO_POSIX# include <sys/types.h># include <sys/stat.h># include <fcntl.h># include <unistd.h>#endif/*********     DEFINES                                          *********/#ifndef BFILEMODE_PROT/*  START-DEFINITIONS  */#include <stdio.h>     /*  For "FILE" definition  */#include <jsconfig.h>  /*  For configurational definitions  */typedef struct BuffFilePage BuffFilePage;struct BuffFilePage {  BuffFilePage *BFP_Next; /*  pointer to next page in linked list  */  /*  PageLen may be smaller than the pagesize for read pages at EOF  */  long          BFP_PageNr,BFP_PageLen;  /*  Actual page  */  char         *BFP_Page;  /*  multiple protections for a region are OK  */  short         BFP_Flags,BFP_Prot;};#define BFP_DIRTY     (1<<0)  /*  page is dirty  */#define BFP_REREAD    (1<<1)  /*  re-read  */typedef struct BuffFile BuffFile;struct BuffFile {  int BF_Type;#ifndef CONFIG_NO_POSIX  int BF_Handle;#else  FILE *BF_Handle;#endif  int BF_PageShift;  int BF_HashLen;  BuffFilePage **BF_HashTab;  /*  For memory mapped I/O  */  char *BF_MMPage;  long BF_MMPageLen;  short BF_MMProt;};/*  For routine bFileOpen  */#define BFILE_WRITE          (1<<0)  /*  Open for r/w (default is rd-only)  */#define BFILE_CREATE         (1<<1)  /*  Create file, deleting old contents  */#define BFILE_MMAP           (1<<2)  /*  Use memory mapped I/O if possible  */#define BFILE_FLOCK          (1<<3)  /*  Lock the whole file after opening  */#define BFILE_FLOCKW         (1<<4)  /*  Same as FLOCK, but wait for others  */#define BFILE_MULTI          (1<<5)  /*  Multiuser support when accessing  *//* ***  For bFileGet  *** */#define BFILEMODE_PROT       (1<<0)  /*  Prevent reusage of the page buffer  */#define BFILEMODE_UNPROT     (1<<1)  /*  Allow reusage of the page buffer  */#define BFILEMODE_CLEARPROT  (1<<2)  /*  Clear any protections   */#define BFILEMODE_DIRTY      (1<<3)  /*  Mark a page dirty  */#define BFILEMODE_REREAD     (1<<4)  /*  Force re-read even if in memory  *//*  If the caller of bFileGet expects the returned length *   to be identical to passed one */#define BFILEMODE_FULLMAP    (1<<5)/*  How to get the current file length. You have to flush the file first!  */#ifndef CONFIG_NO_POSIX# define bFileFLength(bfp)   fdFileLength((bfp)->BF_Handle)#else# define bFileFLength(bfp)   fpFileLength((bfp)->BF_Handle)#endif/*  END-DEFINITIONS  */#endif#ifndef CONFIG_NO_POSIX# define CONFIG_USE_MMAP /*  SVR4 and BSD support it  */#else# undef CONFIG_USE_MMAP  /*  Don't try on non-POSIX systems  */#endif#ifdef CONFIG_USE_MMAP# include <sys/mman.h>#endif/* Using the defaults, the maximum used memory for buffering is *  DEFAULT_HASHLEN * DEFAULT_MAXPAGES * 2^DEFAULT_PAGESHIFT = 512KByte */#ifndef BUFFFILE_DEFHASHLEN# define BUFFFILE_DEFHASHLEN     16#endif#ifndef BUFFFILE_DEFMAXPAGES/*  Maximum number of pages in a hash chain *   before we start to steal pages. */# define BUFFFILE_DEFMAXPAGES     4#endif#ifndef BUFFFILE_DEFPAGESHIFT/*  Default size of pages is 2^13 = 8KByte chunks  */# define BUFFFILE_DEFPAGESHIFT   13#endif/* **  Internal macros  ** */#define BF_PAGESIZE(bfp)           (1 << (bfp)->BF_PageShift)#define BF_PAGEOFFSET(bfp,pageNr)  ((pageNr) << (bfp)->BF_PageShift)#define freePage(p)  (free((p)->BFP_Page),free(p))#define Prototype extern/*********     PROTOTYPES                                       *********/Prototype BuffFile      *bFileOpen(const char *name,int hashLen,int pLenShift,				   int mode);Prototype int            bFileClose(BuffFile *bfp);Prototype int            bFileFlush(BuffFile *bfp,int mode);static int               flushPage(BuffFile *bfp,BuffFilePage *p);Prototype int            bFileTruncate(BuffFile *bfp,long size);Prototype char          *bFileGet(BuffFile *bfp,long offset,long *pLen,				  int mode);Prototype char          *bFileGet2(BuffFile *bfp,long offset,long len,int mode);Prototype int            bFileSet(BuffFile *bfp,long offset,long len,int mode);Prototype int            bFileRead(BuffFile *bfp,void *ptr,long offset,				   long size);Prototype int            bFileWrite(BuffFile *bfp,const void *ptr,long offset,				    long size);Prototype int            bFileByteSet(BuffFile *bfp,int c,long offset,				      long size);Prototype int            bFileByteCopy(BuffFile *bfp,long sOff,long dOff,				       long size);Prototype int            bFileByteMove(BuffFile *bfp,long sOff,long dOff,				       long size);Prototype long           bFileNLocks(BuffFile *bfp);Prototype int            BuffFileMaxPage;/*********     GLOBAL VARIABLES                                 *********/int BuffFileMaxPage = BUFFFILE_DEFMAXPAGES;/*JS**********************************************************************   Opens the named file for buffered I/O, using pLenShift for*    determining the length of a page. mode specifies if the file is*    opened for writing (BFILE_WRITE) or if memory mapped I/O should be*    used if possible (BFILE_MMAP). File growth is not possible when*    using memory mapped I/O.*************************************************************************/BuffFile *bFileOpen(const char *name,int hashLen,int pLenShift,int mode)/************************************************************************/{  BuffFile *bfp;  if((bfp = (BuffFile *)calloc(1,sizeof(*bfp))) == NULL) return(NULL);  bfp->BF_Type = mode;  bfp->BF_HashLen = hashLen ? hashLen : BUFFFILE_DEFHASHLEN;  bfp->BF_PageShift = pLenShift ? pLenShift : BUFFFILE_DEFPAGESHIFT;  bfp->BF_MMPage = NULL;#ifndef CONFIG_NO_POSIX  if((bfp->BF_Handle = open(name,(mode & BFILE_WRITE) ?			    ((mode & BFILE_CREATE) ? (O_RDWR|O_CREAT|O_TRUNC) :			     O_RDWR) : O_RDONLY,0666)) < 0)    goto error;  /*  If required, lock the whole file  */  if(mode & (BFILE_FLOCK | BFILE_FLOCKW)) {    struct flock lock;    lock.l_type   = (mode & BFILE_WRITE) ? F_WRLCK : F_RDLCK;    lock.l_start  = 0;    lock.l_whence = SEEK_SET;    lock.l_len    = 0;    if(fcntl(bfp->BF_Handle,(mode & BFILE_FLOCKW) ? F_SETLKW : F_SETLK,	     &lock) < 0)      goto error;  }#ifdef CONFIG_USE_MMAP  if(mode & BFILE_MMAP) {    struct stat stbuf;    if(fstat(bfp->BF_Handle,&stbuf)) goto error;    if(stbuf.st_size > 0) {      bfp->BF_MMPageLen = stbuf.st_size;      /*  If we open file for writing, restrict memory mapped region to       *   multiples of pages. This will ensure that additional pages       *   that are allocated to enlarge the file start on page boundaries       *   in the file.       */      if(mode & BFILE_WRITE) bfp->BF_MMPageLen &= ~(BF_PAGESIZE(bfp) - 1);      /*  Do not try to map empty regions  */      if(bfp->BF_MMPageLen == 0)	bfp->BF_MMPage = NULL;      else if((bfp->BF_MMPage = mmap(NULL,bfp->BF_MMPageLen,				     (mode & BFILE_WRITE) ?				     (PROT_WRITE | PROT_READ) : PROT_READ,				     MAP_SHARED,bfp->BF_Handle,0)) ==	      (void *)-1) goto error;    }  }#endif#else  /*  Use ANSI-fopen function and prevent additional buffering by stdio  */  if((bfp->BF_Handle = fopen(name,(mode & BFILE_WRITE) ?			     ((mode & BFILE_CREATE) ? "wb+" : "rb+") : "rb"))     == NULL ||     setvbuf(bfp->BF_Handle,NULL,_IONBF,0))    goto error;#endif  if((bfp->BF_HashTab = (BuffFilePage **)calloc(bfp->BF_HashLen,						sizeof(*(bfp->BF_HashTab))))     == NULL)    goto error;  return(bfp);error:#ifndef CONFIG_NO_POSIX  if(bfp->BF_Handle >= 0) close(bfp->BF_Handle);#ifdef CONFIG_USE_MMAP  if(bfp->BF_MMPage) munmap(bfp->BF_MMPage,bfp->BF_MMPageLen);#endif#else  if(bfp->BF_Handle) fclose(bfp->BF_Handle);#endif  if(bfp->BF_HashTab) free(bfp->BF_HashTab);  free(bfp);  return(NULL);}/*JS**********************************************************************   Closes the buffered file, flushing all data.*************************************************************************/int bFileClose(BuffFile *bfp)/************************************************************************/{  int i,ret;  ret = 0;  if(bFileFlush(bfp,0) < 0) ret = -1;  for(i = 0 ; i < bfp->BF_HashLen ; i++) {    BuffFilePage *p,*n;    for(p = bfp->BF_HashTab[i] ; p ; p = n) {      n = p->BFP_Next;      freePage(p);    }  }  free(bfp->BF_HashTab);#ifdef CONFIG_USE_MMAP  if(bfp->BF_MMPage && munmap(bfp->BF_MMPage,bfp->BF_MMPageLen) < 0) ret = -1;#endif  if(#ifndef CONFIG_NO_POSIX    close(bfp->BF_Handle) < 0#else    fclose(bfp->BF_Handle)#endif    ) ret = -1;  free(bfp);  return(ret);}/*JS**********************************************************************   Flushes all dirty buffers to disk. If Bit 0 of mode is set, buffers*    are freed if they exceed the maximum number of buffers. If Bit 1 of*    mode is set, a memory mapped region is extended if necessary to cover*    the whole file. If Bit 2 of mode is set, the dirty flag is not*    deleted when a page is flushed.*************************************************************************/int bFileFlush(BuffFile *bfp,int mode)/************************************************************************/{  int i;  /*  Flush all pages  */  for(i = 0 ; i < bfp->BF_HashLen ; i++) {    BuffFilePage *p;    int count,countUL;    /*  Flush all pages, count whole and unlocked ones  */    for(count = countUL = 0, p = bfp->BF_HashTab[i] ; p ;	p = p->BFP_Next, count++) {      if(p->BFP_Flags & BFP_DIRTY) {	if(flushPage(bfp,p)) goto error;	if(!(mode & 4)) p->BFP_Flags &= ~BFP_DIRTY;      }      if(p->BFP_Prot == 0) countUL++;    }    /*  Free pages?  */    if((mode & 3) && count > BuffFileMaxPage && countUL > 0) {      BuffFilePage *previous;      /*  Start freeing pages (count >= 0) at the end of the list  */      count -= BuffFileMaxPage + countUL;      for(p = bfp->BF_HashTab[i], previous = NULL ; p ; count++)	if(count >= 0 && p->BFP_Prot == 0) {	  BuffFilePage *next = p->BFP_Next;	  if(previous) {	    previous->BFP_Next = next;	  } else {	    bfp->BF_HashTab[i] = next;	  }	  freePage(p);	  p = next; /*  previous doesn't change  */	} else {	  previous = p;	  p = p->BFP_Next;	}    }  }#ifdef CONFIG_USE_MMAP  /*  Try to extend memory mapped region only if file is opened for r/w  */  if((mode & 2) && (bfp->BF_Type & (BFILE_MMAP|BFILE_WRITE)) ==     (BFILE_MMAP|BFILE_WRITE) && bfp->BF_MMProt == 0) {    struct stat stbuf;    long size;    /*  Check if some pages are still locked. Otherwise we     *   might have the memory mapped region and a page     *   pointing to the same file location.     */    for(i = 0 ; i < bfp->BF_HashLen ; i++) {      BuffFilePage *p;      for(p = bfp->BF_HashTab[i] ; p ; p = p->BFP_Next) {	if(p->BFP_Prot) goto ende;	p->BFP_PageNr = -1; /*  mark this page unused  */      }    }    if(fstat(bfp->BF_Handle,&stbuf)) goto error;    /*  Restrict memory mapped region to multiples of pages  */    size = stbuf.st_size & ~(BF_PAGESIZE(bfp) - 1);    /*  Check if file size has changed  */    if(size != bfp->BF_MMPageLen) {      if(bfp->BF_MMPage && munmap(bfp->BF_MMPage,bfp->BF_MMPageLen) < 0)	goto error;      if((bfp->BF_MMPageLen = size) == 0)	bfp->BF_MMPage = NULL;      else if((bfp->BF_MMPage = mmap(NULL,bfp->BF_MMPageLen,				     (PROT_WRITE | PROT_READ),MAP_SHARED,				     bfp->BF_Handle,0)) == (void *)-1)	goto error;    }  }ende:# if defined(__linux__)  if((bfp->BF_Type & (BFILE_MMAP|BFILE_WRITE)) == (BFILE_MMAP|BFILE_WRITE)) {    /*  Schedule memory mapped region for write  */    if(msync(bfp->BF_MMPage,bfp->BF_MMPageLen,MS_ASYNC) < 0) goto error;  }# endif#endif  /*  Flush all data to disk  */#ifndef CONFIG_NO_POSIX#if 0  /*  Prevent to much I/O  */  if(fsync(bfp->BF_Handle) < 0) goto error;#endif#else  if(fflush(bfp->BF_Handle) == EOF) goto error;#endif  return(0);error:  return(-1);}/*JS**********************************************************************   Internal routine to flush contents of a page.*************************************************************************/static int flushPage(BuffFile *bfp,BuffFilePage *p)/************************************************************************/{  if(#ifndef CONFIG_NO_POSIX     lseek(bfp->BF_Handle,BF_PAGEOFFSET(bfp,p->BFP_PageNr),SEEK_SET) < 0 ||     write(bfp->BF_Handle,p->BFP_Page,p->BFP_PageLen) != p->BFP_PageLen#else     fseek(bfp->BF_Handle,BF_PAGEOFFSET(bfp,p->BFP_PageNr),SEEK_SET) ||     fwrite(p->BFP_Page,1,p->BFP_PageLen,bfp->BF_Handle) != p->BFP_PageLen#endif     ) return(-1);  return(0);}/* ERROR-DEFINITIONS from bFileTruncate label _ERR_BFILETRUNC ord 16   Locked pages beyond file size found*//*JS***********************************************************************************************************************************************/int bFileTruncate(BuffFile *bfp,long size)/************************************************************************/{  int i;  for(i = 0 ; i < bfp->BF_HashLen ; i++) {    BuffFilePage *p,*prev,*next;    for(prev = NULL, p = bfp->BF_HashTab[i] ; p ; p = next) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -