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