1 #include "sam.h" 2 3 static Block *blist; 4 5 static int 6 tempdisk(void) 7 { 8 char buf[128]; 9 int i, fd; 10 11 snprint(buf, sizeof buf, "/tmp/X%d.%.4ssam", getpid(), getuser()); 12 for(i='A'; i<='Z'; i++){ 13 buf[5] = i; 14 if(access(buf, AEXIST) == 0) 15 continue; 16 fd = create(buf, ORDWR|ORCLOSE|OCEXEC, 0600); 17 if(fd >= 0) 18 return fd; 19 } 20 return -1; 21 } 22 23 Disk* 24 diskinit() 25 { 26 Disk *d; 27 28 d = emalloc(sizeof(Disk)); 29 d->fd = tempdisk(); 30 if(d->fd < 0){ 31 fprint(2, "sam: can't create temp file: %r\n"); 32 exits("diskinit"); 33 } 34 return d; 35 } 36 37 static 38 uint 39 ntosize(uint n, uint *ip) 40 { 41 uint size; 42 43 if(n > Maxblock) 44 panic("internal error: ntosize"); 45 size = n; 46 if(size & (Blockincr-1)) 47 size += Blockincr - (size & (Blockincr-1)); 48 /* last bucket holds blocks of exactly Maxblock */ 49 if(ip) 50 *ip = size/Blockincr; 51 return size * sizeof(Rune); 52 } 53 54 Block* 55 disknewblock(Disk *d, uint n) 56 { 57 uint i, j, size; 58 Block *b; 59 60 size = ntosize(n, &i); 61 b = d->free[i]; 62 if(b) 63 d->free[i] = b->next; 64 else{ 65 /* allocate in chunks to reduce malloc overhead */ 66 if(blist == nil){ 67 blist = emalloc(100*sizeof(Block)); 68 for(j=0; j<100-1; j++) 69 blist[j].next = &blist[j+1]; 70 } 71 b = blist; 72 blist = b->next; 73 b->addr = d->addr; 74 d->addr += size; 75 } 76 b->n = n; 77 return b; 78 } 79 80 void 81 diskrelease(Disk *d, Block *b) 82 { 83 uint i; 84 85 ntosize(b->n, &i); 86 b->next = d->free[i]; 87 d->free[i] = b; 88 } 89 90 void 91 diskwrite(Disk *d, Block **bp, Rune *r, uint n) 92 { 93 int size, nsize; 94 Block *b; 95 96 b = *bp; 97 size = ntosize(b->n, nil); 98 nsize = ntosize(n, nil); 99 if(size != nsize){ 100 diskrelease(d, b); 101 b = disknewblock(d, n); 102 *bp = b; 103 } 104 if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) 105 panic("write error to temp file"); 106 b->n = n; 107 } 108 109 void 110 diskread(Disk *d, Block *b, Rune *r, uint n) 111 { 112 if(n > b->n) 113 panic("internal error: diskread"); 114 115 ntosize(b->n, nil); /* called only for sanity check on Maxblock */ 116 if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) 117 panic("read error from temp file"); 118 } 119