📄 bufffile.c
字号:
long offset; next = p->BFP_Next; offset = BF_PAGEOFFSET(bfp,p->BFP_PageNr); if((offset + p->BFP_PageLen) > size) { /* Cannot truncate if exceeding page is still locked. * We have a problem here: Counting locks doesn't * provide enough information to decide if the * truncation violates a locked region. We thus * must trust the user who does the truncation. * We only check for the obvious case where the * start of the page lays already behind the new * size. */ if(offset > size && p->BFP_Prot) { JSErrNo = _ERR_BFILETRUNC + 0; goto error; } /* Truncate or free this page */ if(offset < size) { p->BFP_PageLen = size - offset; } else { /* Remove page from linked list */ if(prev) prev->BFP_Next = next; else bfp->BF_HashTab[i] = next; freePage(p); continue; /* prev doesn' change */ } } prev = p; } }#ifndef CONFIG_NO_POSIX if(ftruncate(bfp->BF_Handle,size) < 0) goto error;#endif return(0);error: return(-1);}/* ERROR-DEFINITIONS from bFileGet label _ERR_BFILEGET ord 16 Cannot map complete region End of file*//*JS********************************************************************** Returns the start pointer for the specified region* [offset,offset + *pLen] in the file. The returned length in *pLen* may be shorter, thus requiring additional calls to bFileGet.* Properties for the region may be set immediately using mode:* 'BFILEMODE_PROT' prevents reusage, 'BFILEMODE_UNPROT' allows.* 'BFILEMODE_DIRTY' marks that the region must be written to disk.* 'BFILEMMODE_REREAD' forces re-reading the page.*************************************************************************/char *bFileGet(BuffFile *bfp,long offset,long *pLen,int mode)/************************************************************************/{ BuffFilePage *p,*lastUnlocked,*previous; long len,pageNr; int hash,count,flag; len = *pLen;#ifdef CONFIG_USE_MMAP if(bfp->BF_MMPage) { if(len > 0 ? offset < bfp->BF_MMPageLen : offset <= bfp->BF_MMPageLen) { /* Check if boundary of memory mapped region is exceeded */ if(len > 0) { if((offset + len) > bfp->BF_MMPageLen) { if(mode & BFILEMODE_FULLMAP) goto maperror; *pLen = bfp->BF_MMPageLen - offset; } } else { if((offset + len) < 0) { if(mode & BFILEMODE_FULLMAP) goto maperror; *pLen = -offset; } } if(mode & BFILEMODE_PROT) bfp->BF_MMProt++; if(mode & BFILEMODE_UNPROT) bfp->BF_MMProt--; /* Clearing lock takes precedence */ if(mode & BFILEMODE_CLEARPROT) bfp->BF_MMProt = 0; return(bfp->BF_MMPage + offset); } else if(!(bfp->BF_Type & BFILE_WRITE)) { /* Trying to enlarge file in case of read-only * access doesn't make sense. */ JSErrNo = _ERR_BFILEGET + 1; goto error; } }#endif if(len > 0) { pageNr = offset >> bfp->BF_PageShift; offset &= BF_PAGESIZE(bfp) - 1; } else { offset--; pageNr = offset >> bfp->BF_PageShift; offset &= BF_PAGESIZE(bfp) - 1; offset++; } hash = pageNr % bfp->BF_HashLen; flag = 0; lastUnlocked = NULL; for(count = 0, p = bfp->BF_HashTab[hash], previous = NULL ; p ; previous = p, p = p->BFP_Next, count++) { if(p->BFP_Prot == 0) { lastUnlocked = previous; flag |= 1; /* page found */ } if(p->BFP_PageNr == pageNr) break; } if(p == NULL) { if(count < BuffFileMaxPage || !(flag & 1)) { /* Allocate new page. We have not included the page in the structure * itself to be sure it is correctly aligned. */ if((p = (BuffFilePage *)malloc(sizeof(*p))) == NULL) goto error; if((p->BFP_Page = (char *)malloc(BF_PAGESIZE(bfp))) == NULL) { free(p); goto error; } p->BFP_PageNr = -1; p->BFP_Prot = 0; /* Hang in front of list */ p->BFP_Next = bfp->BF_HashTab[hash]; bfp->BF_HashTab[hash] = p; } else { /* Reuse page and hang in front of list */ if(lastUnlocked) { p = lastUnlocked->BFP_Next; lastUnlocked->BFP_Next = p->BFP_Next; p->BFP_Next = bfp->BF_HashTab[hash]; bfp->BF_HashTab[hash] = p; } else { /* Page is already at head */ p = bfp->BF_HashTab[hash]; } if((p->BFP_Flags & BFP_DIRTY) && flushPage(bfp,p)) goto error; } /* Load page */ p->BFP_Flags = 0; p->BFP_PageNr = pageNr; flag |= 2; } else if((p->BFP_Flags & BFP_REREAD) || (mode & BFILEMODE_REREAD)) { flag |= 2; p->BFP_Flags &= ~BFP_REREAD; } /* Read page? */ if(flag & 2) { if(#ifndef CONFIG_NO_POSIX lseek(bfp->BF_Handle,BF_PAGEOFFSET(bfp,p->BFP_PageNr),SEEK_SET) < 0 || (p->BFP_PageLen = read(bfp->BF_Handle,p->BFP_Page,BF_PAGESIZE(bfp)))#else fseek(bfp->BF_Handle,BF_PAGEOFFSET(bfp,p->BFP_PageNr),SEEK_SET) < 0 || (p->BFP_PageLen = fread(p->BFP_Page,1,BF_PAGESIZE(bfp),bfp->BF_Handle))#endif < 0) goto error; } if(len > 0) { if((offset + len) > p->BFP_PageLen) { if(mode & BFILEMODE_DIRTY) { /* User requested writing, so increase area */ p->BFP_PageLen = MIN(BF_PAGESIZE(bfp),offset + len); if((offset + len) > p->BFP_PageLen) { if(mode & BFILEMODE_FULLMAP) goto maperror; *pLen = p->BFP_PageLen - offset; } } else { /* Check first for EOF before assuming map error */ if((*pLen = p->BFP_PageLen - offset) < 0) { JSErrNo = _ERR_BFILEGET + 1; goto error; } if(mode & BFILEMODE_FULLMAP) goto maperror; } } } else { if(offset > p->BFP_PageLen) { if(mode & BFILEMODE_DIRTY) { /* User requested writing, so increase area */ p->BFP_PageLen = MIN(BF_PAGESIZE(bfp),offset); if((offset + len) < 0) { if(mode & BFILEMODE_FULLMAP) goto maperror; *pLen = -offset; } } else { /* Doesn't work for negative lengths */ JSErrNo = _ERR_BFILEGET + 1; goto error; } } else if((offset + len) < 0) { if(mode & BFILEMODE_FULLMAP) goto maperror; *pLen = -offset; } } if(mode & BFILEMODE_DIRTY) p->BFP_Flags |= BFP_DIRTY; if(mode & BFILEMODE_PROT) p->BFP_Prot++; if(mode & BFILEMODE_UNPROT) p->BFP_Prot--; /* Clearing lock takes precedence */ if(mode & BFILEMODE_CLEARPROT) p->BFP_Prot = 0; return(p->BFP_Page + offset);maperror: JSErrNo = _ERR_BFILEGET + 0;error: return(NULL);}/*JS********************************************************************** Simple interface to bFileGet to avoid pointer argument if one expects* the whole region to be mapped.*************************************************************************/char *bFileGet2(BuffFile *bfp,long offset,long len,int mode)/************************************************************************/{ return(bFileGet(bfp,offset,&len,mode));}/* ERROR-DEFINITIONS from bFileGet label _ERR_BFILESET ord 16 Page not in memory*//*JS********************************************************************** Sets the specified property of the region: 'BFILEMODE_PROT' prevents* reusage, 'BFILEMODE_UNPROT' allows. 'BFILEMODE_DIRTY' marks that the* region must be written to disk.*************************************************************************/int bFileSet(BuffFile *bfp,long offset,long len,int mode)/************************************************************************/{ if(len < 0) { /* If len is negative, simply do it the other way round */ offset += len; len = -len; } while(len > 0) { BuffFilePage *p; long pageNr,pOffset,len2;#ifdef CONFIG_USE_MMAP if(bfp->BF_MMPage && offset < bfp->BF_MMPageLen) { /* Check if boundary of memory mapped region is exceeded */ len2 = MIN(len,bfp->BF_MMPageLen - offset); if(mode & BFILEMODE_PROT) bfp->BF_MMProt++; if(mode & BFILEMODE_UNPROT) bfp->BF_MMProt--; /* Clearing lock takes precedence */ if(mode & BFILEMODE_CLEARPROT) bfp->BF_MMProt = 0; } else#endif { pageNr = offset >> bfp->BF_PageShift; pOffset = offset & (BF_PAGESIZE(bfp) - 1); for(p = bfp->BF_HashTab[pageNr % bfp->BF_HashLen] ; p ; p = p->BFP_Next) if(p->BFP_PageNr == pageNr) break; if(p == NULL) { JSErrNo = _ERR_BFILESET + 0; return(-1); } if(mode & BFILEMODE_DIRTY) p->BFP_Flags |= BFP_DIRTY; if(mode & BFILEMODE_PROT) p->BFP_Prot++; if(mode & BFILEMODE_UNPROT) p->BFP_Prot--; /* Clearing lock takes precedence */ if(mode & BFILEMODE_CLEARPROT) p->BFP_Prot = 0; len2 = MIN(len,BF_PAGESIZE(bfp) - pOffset); } offset += len2; len -= len2; } return(0);}/*JS********************************************************************** Read the specified length into the buffer. The returned length may be* shorter if the end of file is reached.*************************************************************************/int bFileRead(BuffFile *bfp,void *ptr,long offset,long size)/************************************************************************/{ long toRead,l; for(toRead = size ; toRead > 0 ; toRead -= l) { char *adr; /* Try to get as much as possible */ l = toRead; if((adr = bFileGet(bfp,offset,&l,0)) == NULL) return(-1); /* EOF reached? */ if(l == 0) break; memcpy(ptr,adr,l); offset += l; ptr = (void *)((char *)ptr + l); } return(size - toRead);}/*JS********************************************************************** Write the specified length from the buffer to the file. The returned* length may be shorter if an error occured.*************************************************************************/int bFileWrite(BuffFile *bfp,const void *ptr,long offset,long size)/************************************************************************/{ long toWrite,l; for(toWrite = size ; toWrite > 0 ; toWrite -= l) { char *adr; l = toWrite; if((adr = bFileGet(bfp,offset,&l,BFILEMODE_DIRTY)) == NULL) return(-1); memcpy(adr,ptr,l); offset += l; ptr = (void *)((char *)ptr + l); } return(size - toWrite);}/*JS********************************************************************** Set the region from offset to offset+size to the byte c.*************************************************************************/int bFileByteSet(BuffFile *bfp,int c,long offset,long size)/************************************************************************/{ long toSet,l; for(toSet = size ; toSet > 0 ; toSet -= l) { char *adr; l = toSet; if((adr = bFileGet(bfp,offset,&l,BFILEMODE_DIRTY)) == NULL) return(-1); memset(adr,c,l); offset += l; } return(size - toSet);}/*JS********************************************************************** Copys size bytes from offset sOff to dOff. Doesn't work if the areas* overlap.*************************************************************************/int bFileByteCopy(BuffFile *bfp,long sOff,long dOff,long size)/************************************************************************/{ long toCopy,l,l2; for(toCopy = size ; toCopy > 0 ; toCopy -= l2) { char *s,*d; l = l2 = toCopy; if((s = bFileGet(bfp,sOff,&l,BFILEMODE_PROT)) == NULL || (d = bFileGet(bfp,dOff,&l2,BFILEMODE_DIRTY)) == NULL) return(-1); if(l < l2) l2 = l; memcpy(d,s,l2); if(bFileSet(bfp,sOff,l,BFILEMODE_UNPROT) < 0) return(-1); sOff += l2; dOff += l2; } return(size - toCopy);}/*JS********************************************************************** Moves size bytes from offset sOff to dOff. Works also if the areas* overlap.*************************************************************************/int bFileByteMove(BuffFile *bfp,long sOff,long dOff,long size)/************************************************************************/{ long toCopy,l,l2; /* If the destination offset is greater than the source * offset, do it backwards in case areas overlap. */ if(sOff < dOff) { sOff += size; dOff += size; toCopy = -size; } else toCopy = size; for( ; toCopy != 0 ; toCopy -= l2) { char *s,*d; l = l2 = toCopy; if((s = bFileGet(bfp,sOff,&l,BFILEMODE_PROT)) == NULL || (d = bFileGet(bfp,dOff,&l2,BFILEMODE_DIRTY)) == NULL) return(-1); if(toCopy > 0) { if(l < l2) l2 = l; memmove(d,s,l2); } else { if(l > l2) l2 = l; memmove(d + l2,s + l2,-l2); } if(bFileSet(bfp,sOff,l,BFILEMODE_UNPROT) < 0) return(-1); sOff += l2; dOff += l2; } return(size - ABS(toCopy));}/*JS********************************************************************** Count total number of locks currently present on buffered file.*************************************************************************/long bFileNLocks(BuffFile *bfp)/************************************************************************/{ int i; long count; count = bfp->BF_MMProt; for(i = 0 ; i < bfp->BF_HashLen ; i++) { BuffFilePage *p; for(p = bfp->BF_HashTab[i] ; p ; p = p->BFP_Next) count += p->BFP_Prot; } return(count);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -