]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cfs/file.c
show line numbers in dtracy type errors
[plan9front.git] / sys / src / cmd / cfs / file.c
1 #include <u.h>
2 #include <libc.h>
3 #include "cformat.h"
4 #include "lru.h"
5 #include "bcache.h"
6 #include "disk.h"
7 #include "inode.h"
8 #include "file.h"
9
10 /*
11  *  merge data with that which already exists in a block
12  *
13  *  we allow only one range per block, always use the new
14  *  data if the ranges don't overlap.
15  */
16 void
17 fmerge(Dptr *p, char *to, char *from, int start, int len)
18 {
19         int end;
20
21         end = start + len;
22         memmove(to+start, from, end-start);
23
24         /*
25          *  if ranges do not overlap...
26          */
27         if(start>p->end || p->start>end){
28                 /*
29                  *  just use the new data
30                  */
31                 p->start = start;
32                 p->end = end;
33         } else {
34                 /*
35                  *  merge ranges
36                  */
37                 if(start < p->start)
38                         p->start = start;
39                 if(end > p->end)
40                         p->end = end;
41         }
42
43 }
44
45 /*
46  *  write a block (or less) of data onto a disk, follow it with any necessary
47  *  pointer writes.
48  *
49  *      N.B. ordering is everything
50  */
51 int
52 fbwrite(Icache *ic, Ibuf *b, char *a, ulong off, int len)
53 {
54         int wrinode;
55         ulong fbno;
56         Bbuf *dbb;      /* data block */
57         Bbuf *ibb;      /* indirect block */
58         Dptr *p;
59         Dptr t;
60
61         fbno = off / ic->bsize;
62         p = &b->inode.ptr;
63         ibb = 0;
64         wrinode = 0;
65
66         /*
67          *  are there any pages for this inode?
68          */
69         if(p->bno == Notabno){
70                 wrinode = 1;
71                 goto dowrite;
72         }
73         
74         /*
75          *  is it an indirect block?
76          */
77         if(p->bno & Indbno){
78                 ibb = bcread(ic, p->bno);
79                 if(ibb == 0)
80                         return -1;
81                 p = (Dptr*)ibb->data;
82                 p += fbno % ic->p2b;
83                 goto dowrite;
84         }
85
86         /*
87          *  is it the wrong direct block?
88          */
89         if((p->fbno%ic->p2b) != (fbno%ic->p2b)){
90                 /*
91                  *  yes, make an indirect block
92                  */
93                 t = *p;
94                 dpalloc(ic, p);
95                 if(p->bno == Notabno){
96                         *p = t;
97                         return -1;
98                 }
99                 ibb = bcalloc(ic, p->bno);
100                 if(ibb == 0){
101                         *p = t;
102                         return -1;
103                 }
104                 p = (Dptr*)ibb->data;
105                 p += t.fbno % ic->p2b;
106                 *p = t;
107                 p = (Dptr*)ibb->data;
108                 p += fbno % ic->p2b;
109         }
110         wrinode = 1;
111
112 dowrite:
113         /*
114          *  get the data block into the block cache
115          */
116         if(p->bno == Notabno){
117                 /*
118                  *  create a new block
119                  */
120                 dalloc(ic, p);
121                 if(p->bno == Notabno)
122                         return -1;              /* no blocks left (maybe) */
123                 dbb = bcalloc(ic, p->bno);
124         } else {
125                 /*
126                  *  use what's there
127                  */
128                 dbb = bcread(ic, p->bno);
129         }
130         if(dbb == 0)
131                 return -1;
132
133         /*
134          *  merge in the new data
135          */
136         if(p->fbno != fbno){
137                 p->start = p->end = 0;
138                 p->fbno = fbno;
139         }
140         fmerge(p, dbb->data, a, off % ic->bsize, len);
141
142         /*
143          *  write changed blocks back in the
144          *  correct order
145          */
146         bcmark(ic, dbb);
147         if(ibb)
148                 bcmark(ic, ibb);
149         if(wrinode)
150                 if(iwrite(ic, b) < 0)
151                         return -1;
152         return len;
153 }
154
155 /*
156  *  write `n' bytes to the cache
157  *
158  *  return number of bytes written
159  */
160 long
161 fwrite(Icache *ic, Ibuf *b, char *a, ulong off, long n)
162 {
163         int len;
164         long sofar;
165
166         for(sofar = 0; sofar < n; sofar += len){
167                 len = ic->bsize - ((off+sofar)%ic->bsize);
168                 if(len > n - sofar)
169                         len = n - sofar;
170                 if(fbwrite(ic, b, a+sofar, off+sofar, len) < 0)
171                         return sofar;
172         }
173         return sofar;
174 }
175
176 /*
177  *  get a pointer to the next valid data at or after `off'
178  */
179 Dptr *
180 fpget(Icache *ic, Ibuf *b, ulong off)
181 {
182         ulong fbno;
183         long doff;
184         Bbuf *ibb;      /* indirect block */
185         Dptr *p, *p0, *pf;
186
187         fbno = off / ic->bsize;
188         p = &b->inode.ptr;
189
190         /*
191          *  are there any pages for this inode?
192          */
193         if(p->bno == Notabno)
194                 return 0;
195         
196         /*
197          *  if it's a direct block, life is easy?
198          */
199         if(!(p->bno & Indbno)){
200                 /*
201                  *  a direct block, return p if it's at least past what we want
202                  */
203                 if(p->fbno > fbno)
204                         return p;
205                 if(p->fbno < fbno)
206                         return 0;
207                 doff = off % ic->bsize;
208                 if(doff>=p->start && doff<p->end)
209                         return p;
210                 else
211                         return 0;
212         }
213
214         /*
215          *  read the indirect block
216          */
217         ibb = bcread(ic, p->bno);
218         if(ibb == 0)
219                 return 0;
220
221         /*
222          *  find the next valid pointer
223          */
224         p0 = (Dptr*)ibb->data;
225         pf = p0 + (fbno % ic->p2b);
226         if(pf->bno!=Notabno && pf->fbno==fbno){
227                 doff = off % ic->bsize;
228                 if(doff<pf->end)
229                         return pf;
230         }
231         for(p = pf+1; p < p0 + ic->p2b; p++){
232                 fbno++;
233                 if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
234                         return p;
235         }
236         for(p = p0; p < pf; p++){
237                 fbno++;
238                 if(p->fbno==fbno && p->bno!=Notabno && p->start<p->end)
239                         return p;
240         }
241         return 0;
242 }
243
244 /*
245  *  read `n' bytes from the cache.
246  *
247  *  if we hit a gap and we've read something,
248  *  return number of bytes read so far.
249  *
250  *  if we start with a gap, return minus the number of bytes
251  *  to the next data.
252  *
253  *  if there are no bytes cached, return 0.
254  */
255 long
256 fread(Icache *ic, Ibuf *b, char *a, ulong off, long n)
257 {
258         int len, start;
259         long sofar, gap;
260         Dptr *p;
261         Bbuf *bb;
262
263         for(sofar = 0; sofar < n; sofar += len, off += len){
264                 /*
265                  *  get pointer to next data
266                  */
267                 len = n - sofar;
268                 p = fpget(ic, b, off);
269
270                 /*
271                  *  if no more data, return what we have so far
272                  */
273                 if(p == 0)
274                         return sofar;
275
276                 /*
277                  *  if there's a gap, return the size of the gap
278                  */
279                 gap = (ic->bsize*p->fbno + p->start) - off;
280                 if(gap>0)
281                         if(sofar == 0)
282                                 return -gap;
283                         else
284                                 return sofar;
285
286                 /*
287                  *  return what we have
288                  */
289                 bb = bcread(ic, p->bno);
290                 if(bb == 0)
291                         return sofar;
292                 start = p->start - gap;
293                 if(p->end - start < len)
294                         len = p->end - start;
295                 memmove(a + sofar, bb->data + start, len);
296         }
297         return sofar;
298 }