disk.c (2058B)
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 d->addr += size; 79 } 80 b->u.n = n; 81 return b; 82 } 83 84 void 85 diskrelease(Disk *d, Block *b) 86 { 87 uint i; 88 89 ntosize(b->u.n, &i); 90 b->u.next = d->free[i]; 91 d->free[i] = b; 92 } 93 94 void 95 diskwrite(Disk *d, Block **bp, Rune *r, uint n) 96 { 97 int size, nsize; 98 Block *b; 99 100 b = *bp; 101 size = ntosize(b->u.n, nil); 102 nsize = ntosize(n, nil); 103 if(size != nsize){ 104 diskrelease(d, b); 105 b = disknewblock(d, n); 106 *bp = b; 107 } 108 if(pwrite(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) 109 panic("write error to temp file"); 110 b->u.n = n; 111 } 112 113 void 114 diskread(Disk *d, Block *b, Rune *r, uint n) 115 { 116 if(n > b->u.n) 117 panic("internal error: diskread"); 118 119 ntosize(b->u.n, nil); /* called only for sanity check on Maxblock */ 120 if(pread(d->fd, r, n*sizeof(Rune), b->addr) != n*sizeof(Rune)) 121 panic("read error from temp file"); 122 }