#include "sam.h" /* * Guarantee: No compaction from Dread, Dinsert, Ddelete, Dreplace */ static Discdesc desc[NBUFFILES]; static bkalloc(); static bkfree(); static int bkread(); static int bkwrite(); static char tempnam[20]; Discdesc * Dstart() { register i; register Discdesc *dd; register fd; for(i=0, dd=desc; dd->fd; i++, dd++) if(i==NBUFFILES-1) panic("too many buffer files"); if(tempnam[0]==0) sprint(tempnam, "/tmp/sam%d", getpid()); fd=creat(tempnam, 0600); if(fd<0){ unlink(tempnam); fd=creat(tempnam, 0600); } if(fd<0 || (close(fd), fd=open(tempnam, 2))<0) panic("can't create buffer file"); closeonexec(fd); unlink(tempnam); dd->fd=fd; return dd; } Dclosefd() { register i; for(i=0; i<NBUFFILES; i++) if(desc[i].fd) close(desc[i].fd); } Disc * Dopen(dd) Discdesc *dd; { register Disc *d; d=new(Disc, 1); d->desc=dd; return d; } Dclose(d) register Disc *d; { register i; for(i=d->block.nused; --i>=0; ) /* backwards because bkfree() stacks */ bkfree(d, i); gcfree((uchar *)d->block.ptr); free((uchar *)d); } int Dread(d, addr, n, p1) register Disc *d; uchar *addr; int n; Posn p1; { register i, nb, nr; register Posn p=0, p2=p1+n; for(i=0; i<d->block.nused; i++){ if((p+=d->block.ptr[i].nbytes)>p1){ p-=d->block.ptr[i].nbytes; goto out; } } if(p==p1) return 0; /* eof */ return -1; /* past eof */ out: n=0; if(p!=p1){ /* trailing partial block */ nb=d->block.ptr[i].nbytes; if(p2>p+nb) nr=nb-(p1-p); else nr=p2-p1; bkread(d, addr, nr, i, (int)(p1-p)); /* advance to next block */ p+=nb; addr+=nr; n+=nr; i++; } /* whole blocks */ while(p<p2 && (nb=d->block.ptr[i].nbytes)<=p2-p){ if(i>=d->block.nused) return n; /* eof */ bkread(d, addr, nb, i, 0); p+=nb; addr+=nb; n+=nb; i++; } if(p<p2){ /* any initial partial block left? */ nr=p2-p; nb=d->block.ptr[i].nbytes; if(nr>nb) nr=nb; /* eof */ /* just read in the part that survives */ bkread(d, addr, nr, i, 0); n+=nr; } return n; } Dinsert(d, addr, n, p0) register Disc *d; uchar *addr; /* if null, just make space */ int n; Posn p0; { register i, nb, ni; register Posn p=0; uchar hold[BLOCKSIZE]; int nhold; for(i=0; i<d->block.nused; i++){ if((p+=d->block.ptr[i].nbytes)>=p0){ p-=d->block.ptr[i].nbytes; goto out; } } if(p!=p0) panic("Dinsert"); /* beyond eof */ out: d->nbytes+=n; nhold=0; if(i<d->block.nused && (nb=d->block.ptr[i].nbytes)>p0-p){ nhold=nb-(p0-p); bkread(d, hold, nhold, i, (int)(p0-p)); d->block.ptr[i].nbytes-=nhold; /* no write necessary */ } /* insertion point is now at end of block i (which may not exist) */ while(n>0){ if(i<d->block.nused && (nb=d->block.ptr[i].nbytes)<BLOCKSIZE/2){ /* fill this block */ if(nb+n>BLOCKSIZE) ni=BLOCKSIZE/2-nb; else ni=n; if(addr) bkwrite(d, addr, ni, i, nb); nb+=ni; }else{ /* make new block */ if(i<d->block.nused) i++; /* put after this block, if it exists */ bkalloc(d, i); if(n>BLOCKSIZE) ni=BLOCKSIZE/2; else ni=n; if(addr) bkwrite(d, addr, ni, i, 0); nb=ni; } d->block.ptr[i].nbytes=nb; if(addr) addr+=ni; n-=ni; } if(nhold){ if(i<d->block.nused && (nb=d->block.ptr[i].nbytes)+nhold<BLOCKSIZE){ /* fill this block */ bkwrite(d, hold, nhold, i, nb); nb+=nhold; }else{ /* make new block */ if(i<d->block.nused) i++; /* put after this block, if it exists */ bkalloc(d, i); bkwrite(d, hold, nhold, i, 0); nb=nhold; } d->block.ptr[i].nbytes=nb; } } Ddelete(d, p1, p2) register Disc *d; Posn p1, p2; { register i, nb, nd; register Posn p=0; uchar buf[BLOCKSIZE]; for(i=0; i<d->block.nused; i++){ if((p+=d->block.ptr[i].nbytes)>p1){ p-=d->block.ptr[i].nbytes; goto out; } } if(p1!=d->nbytes || p2!=p1) panic("Ddelete"); return; /* beyond eof */ out: d->nbytes-=p2-p1; if(p!=p1){ /* throw away partial block */ nb=d->block.ptr[i].nbytes; bkread(d, buf, nb, i, 0); if(p2>=p+nb) nd=nb-(p1-p); else{ nd=p2-p1; bcopy(buf+(p1-p)+nd, buf+nb, buf+(p1-p), 1); } nb-=nd; bkwrite(d, buf, nb, i, 0); d->block.ptr[i].nbytes=nb; p2-=nd; /* advance to next block */ p+=nb; i++; } /* throw away whole blocks */ while(p<p2 && (nb=d->block.ptr[i].nbytes)<=p2-p){ if(i>=d->block.nused) panic("Ddelete 2"); bkfree(d, i); p2-=nb; } if(p>=p2) /* any initial partial block left to delete? */ return; /* no */ nd=p2-p; nb=d->block.ptr[i].nbytes; /* just read in the part that survives */ bkread(d, buf, nb-=nd, i, nd); /* a little block merging */ if(nb<BLOCKSIZE/2 && i>0 && (nd=d->block.ptr[i-1].nbytes)<BLOCKSIZE/2){ bcopy(buf, buf+nb, buf+nd, -1); bkread(d, buf, nd, --i, 0); bkfree(d, i); nb+=nd; } bkwrite(d, buf, nb, i, 0); d->block.ptr[i].nbytes=nb; } Dreplace(d, p1, p2, addr, n) register Disc *d; Posn p1, p2; uchar *addr; int n; { register i, nb, nr; register Posn p=0; uchar buf[BLOCKSIZE]; if(p2-p1>n) Ddelete(d, p1+n, p2); else if(p2-p1<n) Dinsert(d, (uchar *)0, (int)(n-(p2-p1)), p2); p2=p1+n; /* they're now conformal; replace in place */ for(i=0; i<d->block.nused; i++){ if((p+=d->block.ptr[i].nbytes)>p1){ p-=d->block.ptr[i].nbytes; goto out; } } panic("Dreplace"); out: if(p!=p1){ /* trailing partial block */ nb=d->block.ptr[i].nbytes; bkread(d, buf, nb, i, 0); if(p2>p+nb) nr=nb-(p1-p); else nr=p2-p1; bcopy(addr, addr+nr, buf+p1-p, 1); bkwrite(d, buf, nb, i, 0); /* advance to next block */ p+=nb; addr+=nr; i++; } /* whole blocks */ while(p<p2 && (nb=d->block.ptr[i].nbytes)<=p2-p){ if(i>=d->block.nused) panic("Dreplace 2"); bkwrite(d, addr, nb, i, 0); p+=nb; addr+=nb; i++; } if(p<p2){ /* any initial partial block left? */ nr=p2-p; nb=d->block.ptr[i].nbytes; /* just read in the part that survives */ bkread(d, buf+nr, nb-nr, i, nr); bcopy(addr, addr+nr, buf, 1); bkwrite(d, buf, nb, i, 0); } } static int bkread(d, loc, n, bk, off) Disc *d; uchar *loc; int n; int bk; int off; { Lseek(d->desc->fd, BLOCKSIZE*(long)d->block.ptr[bk].bnum+off, 0); return Read(d->desc->fd, loc, n); } static int bkwrite(d, loc, n, bk, off) Disc *d; uchar *loc; int n; int bk; int off; { Lseek(d->desc->fd, BLOCKSIZE*(long)d->block.ptr[bk].bnum+off, 0); return Write(d->desc->fd, loc, n); } static bkalloc(d, n) register Disc *d; int n; { register Discdesc *dd=d->desc; register bnum; if(dd->free.nused) bnum=dd->free.ptr[--dd->free.nused]; else bnum=dd->nbk++; nocompact(); inslist((List *)&d->block, n, 0L); compactok(); d->block.ptr[n].bnum=bnum; } static bkfree(d, n) Disc *d; int n; { Discdesc *dd=d->desc; nocompact(); inslist(&dd->free, dd->free.nused, (long)d->block.ptr[n].bnum); compactok(); dellist((List *)&d->block, n); }