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