xref: /plan9/sys/src/cmd/cdfs/buf.c (revision f80c7c99152dd8fa8c89f00378a2f8d344303faf)
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