]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cwfs/dentry.c
webfs(4): document -d and -D flags
[plan9front.git] / sys / src / cmd / cwfs / dentry.c
1 #include "all.h"
2
3 Dentry*
4 getdir(Iobuf *p, int slot)
5 {
6         if(!p)
7                 return 0;
8         return (Dentry*)p->iobuf + slot%DIRPERBUF;
9 }
10
11 void
12 accessdir(Iobuf *p, Dentry *d, int f, int uid)
13 {
14         Timet t;
15
16         if(p == nil || p->dev->type == Devro)
17                 return;
18         f &= FREAD|FWRITE;
19         if(f != FWRITE && noatime)
20                 return;
21         p->flags |= Bmod;
22         t = time(nil);
23         d->atime = t;
24         if(f & FWRITE){
25                 d->mtime = t;
26                 d->muid = uid;
27                 d->qid.version++;
28         }
29 }
30
31 void
32 preread(Device *d, Off addr)
33 {
34         Rabuf *rb;
35
36         if(addr == 0)
37                 return;
38         if(raheadq->count+10 >= raheadq->size)  /* ugly knowing layout */
39                 return;
40         lock(&rabuflock);
41         rb = rabuffree;
42         if(rb == 0) {
43                 unlock(&rabuflock);
44                 return;
45         }
46         rabuffree = rb->link;
47         unlock(&rabuflock);
48         rb->dev = d;
49         rb->addr = addr;
50         fs_send(raheadq, rb);
51 }
52
53 Off
54 rel2abs(Iobuf *p, Dentry *d, Off a, int tag, int putb, int uid)
55 {
56         int i;
57         Off addr, qpath, indaddrs = 1, div;
58         Device *dev;
59
60         if(a < 0) {
61                 fprint(2, "rel2abs: neg offset\n");
62                 if(putb)
63                         putbuf(p);
64                 return 0;
65         }
66         dev = p->dev;
67         qpath = d->qid.path;
68
69         /* is `a' a direct block? */
70         if(a < NDBLOCK) {
71                 addr = d->dblock[a];
72                 if(!addr && tag) {
73                         addr = bufalloc(dev, tag, qpath, uid);
74                         d->dblock[a] = addr;
75                         p->flags |= Bmod|Bimm;
76                 }
77                 if(putb)
78                         putbuf(p);
79                 return addr;
80         }
81         a -= NDBLOCK;
82
83         /*
84          * loop through indirect block depths.
85          */
86         for (i = 0; i < NIBLOCK; i++) {
87                 indaddrs *= INDPERBUF;
88                 /* is a's disk addr in this indir block or one of its kids? */
89                 if (a < indaddrs) {
90                         addr = d->iblocks[i];
91                         if(!addr && tag) {
92                                 addr = bufalloc(dev, Tind1+i, qpath, uid);
93                                 d->iblocks[i] = addr;
94                                 p->flags |= Bmod|Bimm;
95                         }
96                         if(putb)
97                                 putbuf(p);
98
99                         div = indaddrs;
100                         for (; i >= 0; i--) {
101                                 div /= INDPERBUF;
102                                 if (div <= 0)
103                                         panic("rel2abs: non-positive divisor");
104                                 addr = indfetch(dev, qpath, addr,
105                                         (a/div)%INDPERBUF, Tind1+i,
106                                         (i == 0? tag: Tind1+i-1), uid);
107                         }
108                         return addr;
109                 }
110                 a -= indaddrs;
111         }
112         if(putb)
113                 putbuf(p);
114
115         /* quintuple-indirect blocks not implemented. */
116         fprint(2, "rel2abs: no %d-deep indirect\n", NIBLOCK+1);
117         return 0;
118 }
119
120 /*
121  * read-ahead strategy
122  * on second block, read RAGAP blocks,
123  * thereafter, read RAGAP ahead of current pos
124  */
125 Off
126 dbufread(Iobuf *p, Dentry *d, Off a, Off ra, int uid)
127 {
128         Off addr;
129
130         if(a == 0)
131                 return 1;
132         if(a == 1 && ra == 1) {
133                 while(ra < a+RAGAP) {
134                         ra++;
135                         addr = rel2abs(p, d, ra, 0, 0, uid);
136                         if(!addr)
137                                 return 0;
138                         preread(p->dev, addr);
139                 }
140                 return ra+1;
141         }
142         if(ra == a+RAGAP) {
143                 addr = rel2abs(p, d, ra, 0, 0, uid);
144                 if(!addr)
145                         return 0;
146                 preread(p->dev, addr);
147                 return ra+1;
148         }
149         return ra;
150 }
151
152 Iobuf*
153 dnodebuf(Iobuf *p, Dentry *d, Off a, int tag, int uid)
154 {
155         Off addr;
156
157         addr = rel2abs(p, d, a, tag, 0, uid);
158         if(addr)
159                 return getbuf(p->dev, addr, Brd);
160         return 0;
161 }
162
163 /*
164  * same as dnodebuf but it calls putbuf(p)
165  * to reduce interference.
166  */
167 Iobuf*
168 dnodebuf1(Iobuf *p, Dentry *d, Off a, int tag, int uid)
169 {
170         Off addr;
171         Device *dev;
172
173         dev = p->dev;
174         addr = rel2abs(p, d, a, tag, 1, uid);
175         if(addr)
176                 return getbuf(dev, addr, Brd);
177         return 0;
178
179 }
180
181 Off
182 indfetch(Device* d, Off qpath, Off addr, Off a, int itag, int tag, int uid)
183 {
184         Iobuf *bp;
185
186         if(!addr)
187                 return 0;
188         bp = getbuf(d, addr, Brd);
189         if(!bp || checktag(bp, itag, qpath)) {
190                 if(!bp) {
191                         fprint(2, "ind fetch bp = 0\n");
192                         return 0;
193                 }
194                 fprint(2, "ind fetch tag\n");
195                 putbuf(bp);
196                 return 0;
197         }
198         addr = ((Off *)bp->iobuf)[a];
199         if(!addr && tag) {
200                 addr = bufalloc(d, tag, qpath, uid);
201                 if(addr) {
202                         ((Off *)bp->iobuf)[a] = addr;
203                         bp->flags |= Bmod;
204                         if(tag == Tdir)
205                                 bp->flags |= Bimm;
206                         settag(bp, itag, qpath);
207                 }
208         }
209         putbuf(bp);
210         return addr;
211 }
212
213 /* return INDPERBUF^exp */
214 Off
215 ibbpow(int exp)
216 {
217         static Off pows[] = {
218                 1,
219                 INDPERBUF,
220                 (Off)INDPERBUF*INDPERBUF,
221                 (Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
222                 (Off)INDPERBUF*(Off)INDPERBUF*(Off)INDPERBUF*INDPERBUF,
223         };
224
225         if (exp < 0)
226                 return 0;
227         else if (exp >= nelem(pows)) {  /* not in table? do it long-hand */
228                 Off indpow = 1;
229
230                 while (exp-- > 0 && indpow > 0)
231                         indpow *= INDPERBUF;
232                 return indpow;
233         } else
234                 return pows[exp];
235 }
236
237 /* return sum of INDPERBUF^n for 1 ≤ n ≤ exp */
238 Off
239 ibbpowsum(int exp)
240 {
241         Off indsum = 0;
242
243         for (; exp > 0; exp--)
244                 indsum += ibbpow(exp);
245         return indsum;
246 }
247
248 /* zero bytes past new file length; return an error code */
249 int
250 trunczero(Truncstate *ts)
251 {
252         int blkoff = ts->newsize % BUFSIZE;
253         Iobuf *pd;
254
255         pd = dnodebuf(ts->p, ts->d, ts->lastblk, Tfile, ts->uid);
256         if (pd == nil || checktag(pd, Tfile, QPNONE)) {
257                 if (pd != nil)
258                         putbuf(pd);
259                 ts->err = Ephase;
260                 return Ephase;
261         }
262         memset(pd->iobuf+blkoff, 0, BUFSIZE - blkoff);
263         putbuf(pd);
264         return 0;
265 }
266
267 /*
268  * truncate d (in p) to length `newsize'.
269  * if larger, just increase size.
270  * if smaller, deallocate blocks after last one
271  * still in file at new size.  last byte to keep
272  * is newsize-1, due to zero origin.
273  * we free in forward order because it's simpler to get right.
274  * if the final block at the new size is partially-filled,
275  * zero the remainder.
276  */
277 int
278 dtrunclen(Iobuf *p, Dentry *d, Off newsize, int uid)
279 {
280         int i, pastlast;
281         Truncstate trunc;
282
283         if (newsize <= 0) {
284                 dtrunc(p, d, uid);
285                 return 0;
286         }
287         memset(&trunc, 0, sizeof trunc);
288         trunc.d = d;
289         trunc.p = p;
290         trunc.uid = uid;
291         trunc.newsize = newsize;
292         trunc.lastblk = newsize/BUFSIZE;
293         if (newsize % BUFSIZE == 0)
294                 trunc.lastblk--;
295         else
296                 trunczero(&trunc);
297         for (i = 0; i < NDBLOCK; i++)
298                 if (trunc.pastlast) {
299                         trunc.relblk = i;
300                         buffree(p->dev, d->dblock[i], 0, &trunc);
301                         d->dblock[i] = 0;
302                 } else if (i == trunc.lastblk)
303                         trunc.pastlast = 1;
304         trunc.relblk = NDBLOCK;
305         for (i = 0; i < NIBLOCK; i++) {
306                 pastlast = trunc.pastlast;
307                 buffree(p->dev, d->iblocks[i], i+1, &trunc);
308                 if (pastlast)
309                         d->iblocks[i] = 0;
310         }
311
312         d->size = newsize;
313         p->flags |= Bmod|Bimm;
314         accessdir(p, d, FWRITE, uid);
315         return trunc.err;
316 }
317
318 /*
319  * truncate d (in p) to zero length.
320  * freeing blocks in reverse order is traditional, from Unix,
321  * in an attempt to keep the free list contiguous.
322  */
323 void
324 dtrunc(Iobuf *p, Dentry *d, int uid)
325 {
326         int i;
327
328         for (i = NIBLOCK-1; i >= 0; i--) {
329                 buffree(p->dev, d->iblocks[i], i+1, nil);
330                 d->iblocks[i] = 0;
331         }
332         for (i = NDBLOCK-1; i >= 0; i--) {
333                 buffree(p->dev, d->dblock[i], 0, nil);
334                 d->dblock[i] = 0;
335         }
336         d->size = 0;
337         p->flags |= Bmod|Bimm;
338         accessdir(p, d, FWRITE, uid);
339 }