|  | #include "sam.h" | 
|  |  | 
|  | static	Block	*blist; | 
|  |  | 
|  | #if 0 | 
|  | static int | 
|  | tempdisk(void) | 
|  | { | 
|  | char buf[128]; | 
|  | int i, fd; | 
|  |  | 
|  | snprint(buf, sizeof buf, "/tmp/X%d.%.4ssam", getpid(), getuser()); | 
|  | for(i='A'; i<='Z'; i++){ | 
|  | buf[5] = i; | 
|  | if(access(buf, AEXIST) == 0) | 
|  | continue; | 
|  | fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600); | 
|  | if(fd >= 0) | 
|  | return fd; | 
|  | } | 
|  | return -1; | 
|  | } | 
|  | #else | 
|  | extern int tempdisk(void); | 
|  | #endif | 
|  |  | 
|  | Disk* | 
|  | diskinit(void) | 
|  | { | 
|  | Disk *d; | 
|  |  | 
|  | d = emalloc(sizeof(Disk)); | 
|  | d->fd = tempdisk(); | 
|  | if(d->fd < 0){ | 
|  | fprint(2, "sam: can't create temp file: %r\n"); | 
|  | exits("diskinit"); | 
|  | } | 
|  | return d; | 
|  | } | 
|  |  | 
|  | static | 
|  | uint | 
|  | ntosize(uint n, uint *ip) | 
|  | { | 
|  | uint size; | 
|  |  | 
|  | if(n > Maxblock) | 
|  | panic("internal error: ntosize"); | 
|  | size = n; | 
|  | if(size & (Blockincr-1)) | 
|  | size += Blockincr - (size & (Blockincr-1)); | 
|  | /* last bucket holds blocks of exactly Maxblock */ | 
|  | if(ip) | 
|  | *ip = size/Blockincr; | 
|  | return size * sizeof(Rune); | 
|  | } | 
|  |  | 
|  | Block* | 
|  | disknewblock(Disk *d, uint n) | 
|  | { | 
|  | uint i, j, size; | 
|  | Block *b; | 
|  |  | 
|  | size = ntosize(n, &i); | 
|  | b = d->free[i]; | 
|  | if(b) | 
|  | d->free[i] = b->u.next; | 
|  | else{ | 
|  | /* allocate in chunks to reduce malloc overhead */ | 
|  | if(blist == nil){ | 
|  | blist = emalloc(100*sizeof(Block)); | 
|  | for(j=0; j<100-1; j++) | 
|  | blist[j].u.next = &blist[j+1]; | 
|  | } | 
|  | b = blist; | 
|  | blist = b->u.next; | 
|  | b->addr = d->addr; | 
|  | if(d->addr+size < d->addr){ | 
|  | panic("temp file overflow"); | 
|  | } | 
|  | d->addr += size; | 
|  | } | 
|  | b->u.n = n; | 
|  | return b; | 
|  | } | 
|  |  | 
|  | void | 
|  | diskrelease(Disk *d, Block *b) | 
|  | { | 
|  | uint i; | 
|  |  | 
|  | ntosize(b->u.n, &i); | 
|  | b->u.next = d->free[i]; | 
|  | d->free[i] = b; | 
|  | } | 
|  |  | 
|  | void | 
|  | diskwrite(Disk *d, Block **bp, Rune *r, uint n) | 
|  | { | 
|  | int size, nsize; | 
|  | Block *b; | 
|  |  | 
|  | b = *bp; | 
|  | size = ntosize(b->u.n, nil); | 
|  | nsize = ntosize(n, nil); | 
|  | if(size != nsize){ | 
|  | diskrelease(d, b); | 
|  | b = disknewblock(d, n); | 
|  | *bp = b; | 
|  | } | 
|  | if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) | 
|  | panic("write error to temp file"); | 
|  | b->u.n = n; | 
|  | } | 
|  |  | 
|  | void | 
|  | diskread(Disk *d, Block *b, Rune *r, uint n) | 
|  | { | 
|  | if(n > b->u.n) | 
|  | panic("internal error: diskread"); | 
|  |  | 
|  | ntosize(b->u.n, nil);	/* called only for sanity check on Maxblock */ | 
|  | if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) | 
|  | panic("read error from temp file"); | 
|  | } |