1 /* 2 * Buffered I/O on block devices. 3 * Write buffering ignores offset. 4 */ 5 6 #include <u.h> 7 #include <libc.h> 8 #include <disk.h> 9 #include "dat.h" 10 #include "fns.h" 11 12 Buf* 13 bopen(long (*fn)(Buf*, void*, long, ulong), int omode, int bs, int nblock) 14 { 15 Buf *b; 16 17 assert(omode == OREAD || OWRITE); 18 assert(bs > 0 && nblock > 0); 19 assert(fn != nil); 20 21 b = emalloc(sizeof(*b)); 22 b->data = emalloc(bs*nblock); 23 b->ndata = 0; 24 b->nblock = nblock; 25 b->bs = bs; 26 b->omode = omode; 27 b->fn = fn; /* function to read or write bs-byte blocks */ 28 29 return b; 30 } 31 32 long 33 bread(Buf *b, void *v, long n, vlong off) 34 { 35 long m; 36 vlong noff; 37 38 assert(b->omode == OREAD); 39 40 /* Refill buffer */ 41 if(b->off > off || off >= b->off+b->ndata) { 42 noff = off - off % b->bs; 43 if(vflag > 1) 44 fprint(2, "try refill at %lld...", noff); 45 if((m = b->fn(b, b->data, b->nblock, noff/b->bs)) <= 0) { 46 if (vflag) 47 fprint(2, "read failed: %r\n"); 48 return m; 49 } 50 b->ndata = b->bs * m; 51 b->off = noff; 52 if(vflag > 1) 53 fprint(2, "got %ld\n", b->ndata); 54 } 55 56 // fprint(2, "read %ld at %ld\n", n, off); 57 /* Satisfy request from buffer */ 58 off -= b->off; 59 if(n > b->ndata - off) 60 n = b->ndata - off; 61 memmove(v, b->data+off, n); 62 return n; 63 } 64 65 long 66 bwrite(Buf *b, void *v, long n) 67 { 68 long on, m, mdata; 69 uchar *p; 70 71 p = v; 72 on = n; 73 74 /* Fill buffer */ 75 mdata = b->bs*b->nblock; 76 m = mdata - b->ndata; 77 if(m > n) 78 m = n; 79 memmove(b->data+b->ndata, p, m); 80 p += m; 81 n -= m; 82 b->ndata += m; 83 84 /* Flush buffer */ 85 if(b->ndata == mdata) { 86 if(b->fn(b, b->data, b->nblock, 0) < 0) { 87 if(vflag) 88 fprint(2, "write fails: %r\n"); 89 return -1; 90 } 91 b->ndata = 0; 92 } 93 94 /* For now, don't worry about big writes; 9P only does 8k */ 95 assert(n < mdata); 96 97 /* Add remainder to buffer */ 98 if(n) { 99 memmove(b->data, p, n); 100 b->ndata = n; 101 } 102 103 return on; 104 } 105 106 void 107 bterm(Buf *b) 108 { 109 /* DVD & BD prefer full ecc blocks (tracks), but can cope with less */ 110 if(b->omode == OWRITE && b->ndata) 111 b->fn(b, b->data, (b->ndata + b->bs - 1)/b->bs, 0); 112 113 free(b->data); 114 free(b); 115 } 116