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*
bopen(long (* fn)(Buf *,void *,long,ulong),int omode,int bs,int nblock)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
bread(Buf * b,void * v,long n,vlong off)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
bwrite(Buf * b,void * v,long n)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
bterm(Buf * b)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