1d9306527SDavid du Colombier #include "stdinc.h"
2d9306527SDavid du Colombier #include "vac.h"
3d9306527SDavid du Colombier #include "dat.h"
4d9306527SDavid du Colombier #include "fns.h"
5d9306527SDavid du Colombier #include "error.h"
6d9306527SDavid du Colombier
7d9306527SDavid du Colombier typedef struct MetaChunk MetaChunk;
8d9306527SDavid du Colombier
9d9306527SDavid du Colombier struct MetaChunk {
10d9306527SDavid du Colombier ushort offset;
11d9306527SDavid du Colombier ushort size;
12d9306527SDavid du Colombier ushort index;
13d9306527SDavid du Colombier };
14d9306527SDavid du Colombier
15*3be74836SDavid du Colombier static int stringunpack(char **s, uchar **p, int *n);
16d9306527SDavid du Colombier
17d9306527SDavid du Colombier /*
18d9306527SDavid du Colombier * integer conversion routines
19d9306527SDavid du Colombier */
20d9306527SDavid du Colombier #define U8GET(p) ((p)[0])
21d9306527SDavid du Colombier #define U16GET(p) (((p)[0]<<8)|(p)[1])
22d9306527SDavid du Colombier #define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
23d9306527SDavid du Colombier #define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
24d9306527SDavid du Colombier #define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
25d9306527SDavid du Colombier
26*3be74836SDavid du Colombier #define U8PUT(p,v) (p)[0]=(v)&0xFF
27*3be74836SDavid du Colombier #define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
28*3be74836SDavid du Colombier #define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
29d9306527SDavid du Colombier #define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
30d9306527SDavid du Colombier #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
31d9306527SDavid du Colombier
32d9306527SDavid du Colombier static int
stringunpack(char ** s,uchar ** p,int * n)33*3be74836SDavid du Colombier stringunpack(char **s, uchar **p, int *n)
34d9306527SDavid du Colombier {
35d9306527SDavid du Colombier int nn;
36d9306527SDavid du Colombier
37d9306527SDavid du Colombier if(*n < 2)
38*3be74836SDavid du Colombier return -1;
39d9306527SDavid du Colombier
40d9306527SDavid du Colombier nn = U16GET(*p);
41d9306527SDavid du Colombier *p += 2;
42d9306527SDavid du Colombier *n -= 2;
43d9306527SDavid du Colombier if(nn > *n)
44*3be74836SDavid du Colombier return -1;
45*3be74836SDavid du Colombier *s = vtmalloc(nn+1);
46d9306527SDavid du Colombier memmove(*s, *p, nn);
47d9306527SDavid du Colombier (*s)[nn] = 0;
48d9306527SDavid du Colombier *p += nn;
49d9306527SDavid du Colombier *n -= nn;
50*3be74836SDavid du Colombier return 0;
51d9306527SDavid du Colombier }
52d9306527SDavid du Colombier
53d9306527SDavid du Colombier static int
stringpack(char * s,uchar * p)54*3be74836SDavid du Colombier stringpack(char *s, uchar *p)
55d9306527SDavid du Colombier {
56d9306527SDavid du Colombier int n;
57d9306527SDavid du Colombier
58d9306527SDavid du Colombier n = strlen(s);
59d9306527SDavid du Colombier U16PUT(p, n);
60d9306527SDavid du Colombier memmove(p+2, s, n);
61d9306527SDavid du Colombier return n+2;
62d9306527SDavid du Colombier }
63d9306527SDavid du Colombier
64d9306527SDavid du Colombier
65d9306527SDavid du Colombier int
mbunpack(MetaBlock * mb,uchar * p,int n)66*3be74836SDavid du Colombier mbunpack(MetaBlock *mb, uchar *p, int n)
67d9306527SDavid du Colombier {
68d9306527SDavid du Colombier u32int magic;
69d9306527SDavid du Colombier
70d9306527SDavid du Colombier mb->maxsize = n;
71d9306527SDavid du Colombier mb->buf = p;
72d9306527SDavid du Colombier
73d9306527SDavid du Colombier if(n == 0) {
74d9306527SDavid du Colombier memset(mb, 0, sizeof(MetaBlock));
75*3be74836SDavid du Colombier return 0;
76d9306527SDavid du Colombier }
77d9306527SDavid du Colombier
78d9306527SDavid du Colombier magic = U32GET(p);
79d9306527SDavid du Colombier if(magic != MetaMagic && magic != MetaMagic+1) {
80*3be74836SDavid du Colombier werrstr("bad meta block magic");
81*3be74836SDavid du Colombier return -1;
82d9306527SDavid du Colombier }
83d9306527SDavid du Colombier mb->size = U16GET(p+4);
84d9306527SDavid du Colombier mb->free = U16GET(p+6);
85d9306527SDavid du Colombier mb->maxindex = U16GET(p+8);
86d9306527SDavid du Colombier mb->nindex = U16GET(p+10);
87d9306527SDavid du Colombier mb->unbotch = (magic == MetaMagic+1);
88d9306527SDavid du Colombier
89d9306527SDavid du Colombier if(mb->size > n) {
90*3be74836SDavid du Colombier werrstr("bad meta block size");
91*3be74836SDavid du Colombier return -1;
92d9306527SDavid du Colombier }
93d9306527SDavid du Colombier p += MetaHeaderSize;
94d9306527SDavid du Colombier n -= MetaHeaderSize;
95d9306527SDavid du Colombier
96d9306527SDavid du Colombier USED(p);
97d9306527SDavid du Colombier if(n < mb->maxindex*MetaIndexSize) {
98*3be74836SDavid du Colombier werrstr("truncated meta block 2");
99*3be74836SDavid du Colombier return -1;
100d9306527SDavid du Colombier }
101*3be74836SDavid du Colombier return 0;
10249223a73SDavid du Colombier }
103d9306527SDavid du Colombier
104d9306527SDavid du Colombier void
mbpack(MetaBlock * mb)105*3be74836SDavid du Colombier mbpack(MetaBlock *mb)
106d9306527SDavid du Colombier {
107d9306527SDavid du Colombier uchar *p;
108d9306527SDavid du Colombier
109d9306527SDavid du Colombier p = mb->buf;
110d9306527SDavid du Colombier
111d9306527SDavid du Colombier U32PUT(p, MetaMagic);
112d9306527SDavid du Colombier U16PUT(p+4, mb->size);
113d9306527SDavid du Colombier U16PUT(p+6, mb->free);
114d9306527SDavid du Colombier U16PUT(p+8, mb->maxindex);
115d9306527SDavid du Colombier U16PUT(p+10, mb->nindex);
116d9306527SDavid du Colombier }
117d9306527SDavid du Colombier
118d9306527SDavid du Colombier
119d9306527SDavid du Colombier void
mbdelete(MetaBlock * mb,int i,MetaEntry * me)120*3be74836SDavid du Colombier mbdelete(MetaBlock *mb, int i, MetaEntry *me)
121d9306527SDavid du Colombier {
122d9306527SDavid du Colombier uchar *p;
123d9306527SDavid du Colombier int n;
124d9306527SDavid du Colombier
125d9306527SDavid du Colombier assert(i < mb->nindex);
126d9306527SDavid du Colombier
127d9306527SDavid du Colombier if(me->p - mb->buf + me->size == mb->size)
128d9306527SDavid du Colombier mb->size -= me->size;
129d9306527SDavid du Colombier else
130d9306527SDavid du Colombier mb->free += me->size;
131d9306527SDavid du Colombier
132d9306527SDavid du Colombier p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
133d9306527SDavid du Colombier n = (mb->nindex-i-1)*MetaIndexSize;
134d9306527SDavid du Colombier memmove(p, p+MetaIndexSize, n);
135d9306527SDavid du Colombier memset(p+n, 0, MetaIndexSize);
136d9306527SDavid du Colombier mb->nindex--;
137d9306527SDavid du Colombier }
138d9306527SDavid du Colombier
139d9306527SDavid du Colombier void
mbinsert(MetaBlock * mb,int i,MetaEntry * me)140*3be74836SDavid du Colombier mbinsert(MetaBlock *mb, int i, MetaEntry *me)
141d9306527SDavid du Colombier {
142d9306527SDavid du Colombier uchar *p;
143d9306527SDavid du Colombier int o, n;
144d9306527SDavid du Colombier
145d9306527SDavid du Colombier assert(mb->nindex < mb->maxindex);
146d9306527SDavid du Colombier
147d9306527SDavid du Colombier o = me->p - mb->buf;
148d9306527SDavid du Colombier n = me->size;
149d9306527SDavid du Colombier if(o+n > mb->size) {
150d9306527SDavid du Colombier mb->free -= mb->size - o;
151d9306527SDavid du Colombier mb->size = o + n;
152d9306527SDavid du Colombier } else
153d9306527SDavid du Colombier mb->free -= n;
154d9306527SDavid du Colombier
155d9306527SDavid du Colombier p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
156d9306527SDavid du Colombier n = (mb->nindex-i)*MetaIndexSize;
157d9306527SDavid du Colombier memmove(p+MetaIndexSize, p, n);
158d9306527SDavid du Colombier U16PUT(p, me->p - mb->buf);
159d9306527SDavid du Colombier U16PUT(p+2, me->size);
160d9306527SDavid du Colombier mb->nindex++;
161d9306527SDavid du Colombier }
162d9306527SDavid du Colombier
163d9306527SDavid du Colombier int
meunpack(MetaEntry * me,MetaBlock * mb,int i)164*3be74836SDavid du Colombier meunpack(MetaEntry *me, MetaBlock *mb, int i)
165d9306527SDavid du Colombier {
166d9306527SDavid du Colombier uchar *p;
167d9306527SDavid du Colombier int eo, en;
168d9306527SDavid du Colombier
169d9306527SDavid du Colombier if(i < 0 || i >= mb->nindex) {
170*3be74836SDavid du Colombier werrstr("bad meta entry index");
171*3be74836SDavid du Colombier return -1;
172d9306527SDavid du Colombier }
173d9306527SDavid du Colombier
174d9306527SDavid du Colombier p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
175d9306527SDavid du Colombier eo = U16GET(p);
176d9306527SDavid du Colombier en = U16GET(p+2);
177d9306527SDavid du Colombier
178d9306527SDavid du Colombier if(0)print("eo = %d en = %d\n", eo, en);
179d9306527SDavid du Colombier if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
180*3be74836SDavid du Colombier werrstr("corrupted entry in meta block");
181*3be74836SDavid du Colombier return -1;
182d9306527SDavid du Colombier }
183d9306527SDavid du Colombier
184d9306527SDavid du Colombier if(eo+en > mb->size) {
185*3be74836SDavid du Colombier werrstr("truncated meta block");
186*3be74836SDavid du Colombier return -1;
187d9306527SDavid du Colombier }
188d9306527SDavid du Colombier
189d9306527SDavid du Colombier p = mb->buf + eo;
190d9306527SDavid du Colombier
191d9306527SDavid du Colombier /* make sure entry looks ok and includes an elem name */
192d9306527SDavid du Colombier if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
193*3be74836SDavid du Colombier werrstr("corrupted meta block entry");
194*3be74836SDavid du Colombier return -1;
195d9306527SDavid du Colombier }
196d9306527SDavid du Colombier
197d9306527SDavid du Colombier me->p = p;
198d9306527SDavid du Colombier me->size = en;
199d9306527SDavid du Colombier
200*3be74836SDavid du Colombier return 0;
201d9306527SDavid du Colombier }
202d9306527SDavid du Colombier
203*3be74836SDavid du Colombier /* assumes a small amount of checking has been done in mbentry */
204d9306527SDavid du Colombier int
mecmp(MetaEntry * me,char * s)205*3be74836SDavid du Colombier mecmp(MetaEntry *me, char *s)
206d9306527SDavid du Colombier {
207d9306527SDavid du Colombier int n;
208d9306527SDavid du Colombier uchar *p;
209d9306527SDavid du Colombier
210d9306527SDavid du Colombier p = me->p;
211d9306527SDavid du Colombier
212d9306527SDavid du Colombier p += 6;
213d9306527SDavid du Colombier n = U16GET(p);
214d9306527SDavid du Colombier p += 2;
215d9306527SDavid du Colombier
216d9306527SDavid du Colombier assert(n + 8 < me->size);
217d9306527SDavid du Colombier
218d9306527SDavid du Colombier while(n > 0) {
219d9306527SDavid du Colombier if(*s == 0)
220d9306527SDavid du Colombier return -1;
221d9306527SDavid du Colombier if(*p < (uchar)*s)
222d9306527SDavid du Colombier return -1;
223d9306527SDavid du Colombier if(*p > (uchar)*s)
224d9306527SDavid du Colombier return 1;
225d9306527SDavid du Colombier p++;
226d9306527SDavid du Colombier s++;
227d9306527SDavid du Colombier n--;
228d9306527SDavid du Colombier }
229d9306527SDavid du Colombier return *s != 0;
230d9306527SDavid du Colombier }
231d9306527SDavid du Colombier
232d9306527SDavid du Colombier int
mecmpnew(MetaEntry * me,char * s)233*3be74836SDavid du Colombier mecmpnew(MetaEntry *me, char *s)
234d9306527SDavid du Colombier {
235d9306527SDavid du Colombier int n;
236d9306527SDavid du Colombier uchar *p;
237d9306527SDavid du Colombier
238d9306527SDavid du Colombier p = me->p;
239d9306527SDavid du Colombier
240d9306527SDavid du Colombier p += 6;
241d9306527SDavid du Colombier n = U16GET(p);
242d9306527SDavid du Colombier p += 2;
243d9306527SDavid du Colombier
244d9306527SDavid du Colombier assert(n + 8 < me->size);
245d9306527SDavid du Colombier
246d9306527SDavid du Colombier while(n > 0) {
247d9306527SDavid du Colombier if(*s == 0)
248d9306527SDavid du Colombier return 1;
249d9306527SDavid du Colombier if(*p < (uchar)*s)
250d9306527SDavid du Colombier return -1;
251d9306527SDavid du Colombier if(*p > (uchar)*s)
252d9306527SDavid du Colombier return 1;
253d9306527SDavid du Colombier p++;
254d9306527SDavid du Colombier s++;
255d9306527SDavid du Colombier n--;
256d9306527SDavid du Colombier }
257d9306527SDavid du Colombier return -(*s != 0);
258d9306527SDavid du Colombier }
259d9306527SDavid du Colombier
260d9306527SDavid du Colombier static int
offsetcmp(const void * s0,const void * s1)261*3be74836SDavid du Colombier offsetcmp(const void *s0, const void *s1)
262d9306527SDavid du Colombier {
263*3be74836SDavid du Colombier const MetaChunk *mc0, *mc1;
264d9306527SDavid du Colombier
265d9306527SDavid du Colombier mc0 = s0;
266d9306527SDavid du Colombier mc1 = s1;
267d9306527SDavid du Colombier if(mc0->offset < mc1->offset)
268d9306527SDavid du Colombier return -1;
269d9306527SDavid du Colombier if(mc0->offset > mc1->offset)
270d9306527SDavid du Colombier return 1;
271d9306527SDavid du Colombier return 0;
272d9306527SDavid du Colombier }
273d9306527SDavid du Colombier
274d9306527SDavid du Colombier static MetaChunk *
metachunks(MetaBlock * mb)275*3be74836SDavid du Colombier metachunks(MetaBlock *mb)
276d9306527SDavid du Colombier {
277d9306527SDavid du Colombier MetaChunk *mc;
278d9306527SDavid du Colombier int oo, o, n, i;
279d9306527SDavid du Colombier uchar *p;
280d9306527SDavid du Colombier
281*3be74836SDavid du Colombier mc = vtmalloc(mb->nindex*sizeof(MetaChunk));
282d9306527SDavid du Colombier p = mb->buf + MetaHeaderSize;
283d9306527SDavid du Colombier for(i = 0; i<mb->nindex; i++) {
284d9306527SDavid du Colombier mc[i].offset = U16GET(p);
285d9306527SDavid du Colombier mc[i].size = U16GET(p+2);
286d9306527SDavid du Colombier mc[i].index = i;
287d9306527SDavid du Colombier p += MetaIndexSize;
288d9306527SDavid du Colombier }
289d9306527SDavid du Colombier
290*3be74836SDavid du Colombier qsort(mc, mb->nindex, sizeof(MetaChunk), offsetcmp);
291d9306527SDavid du Colombier
292d9306527SDavid du Colombier /* check block looks ok */
293d9306527SDavid du Colombier oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
294d9306527SDavid du Colombier o = oo;
295d9306527SDavid du Colombier n = 0;
296d9306527SDavid du Colombier for(i=0; i<mb->nindex; i++) {
297d9306527SDavid du Colombier o = mc[i].offset;
298d9306527SDavid du Colombier n = mc[i].size;
299d9306527SDavid du Colombier if(o < oo)
300d9306527SDavid du Colombier goto Err;
301d9306527SDavid du Colombier oo += n;
302d9306527SDavid du Colombier }
303d9306527SDavid du Colombier if(o+n <= mb->size)
304d9306527SDavid du Colombier goto Err;
305d9306527SDavid du Colombier if(mb->size - oo != mb->free)
306d9306527SDavid du Colombier goto Err;
307d9306527SDavid du Colombier
308d9306527SDavid du Colombier return mc;
309d9306527SDavid du Colombier Err:
310*3be74836SDavid du Colombier vtfree(mc);
311d9306527SDavid du Colombier return nil;
312d9306527SDavid du Colombier }
313d9306527SDavid du Colombier
314d9306527SDavid du Colombier static void
mbcompact(MetaBlock * mb,MetaChunk * mc)315*3be74836SDavid du Colombier mbcompact(MetaBlock *mb, MetaChunk *mc)
316d9306527SDavid du Colombier {
317d9306527SDavid du Colombier int oo, o, n, i;
318d9306527SDavid du Colombier
319d9306527SDavid du Colombier oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
320d9306527SDavid du Colombier
321d9306527SDavid du Colombier for(i=0; i<mb->nindex; i++) {
322d9306527SDavid du Colombier o = mc[i].offset;
323d9306527SDavid du Colombier n = mc[i].size;
324d9306527SDavid du Colombier if(o != oo) {
325d9306527SDavid du Colombier memmove(mb->buf + oo, mb->buf + o, n);
326d9306527SDavid du Colombier U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
327d9306527SDavid du Colombier }
328d9306527SDavid du Colombier oo += n;
329d9306527SDavid du Colombier }
330d9306527SDavid du Colombier
331d9306527SDavid du Colombier mb->size = oo;
332d9306527SDavid du Colombier mb->free = 0;
333d9306527SDavid du Colombier }
334d9306527SDavid du Colombier
335d9306527SDavid du Colombier uchar *
mballoc(MetaBlock * mb,int n)336*3be74836SDavid du Colombier mballoc(MetaBlock *mb, int n)
337d9306527SDavid du Colombier {
338d9306527SDavid du Colombier int i, o;
339d9306527SDavid du Colombier MetaChunk *mc;
340d9306527SDavid du Colombier
341d9306527SDavid du Colombier /* off the end */
342d9306527SDavid du Colombier if(mb->maxsize - mb->size >= n)
343d9306527SDavid du Colombier return mb->buf + mb->size;
344d9306527SDavid du Colombier
345d9306527SDavid du Colombier /* check if possible */
346d9306527SDavid du Colombier if(mb->maxsize - mb->size + mb->free < n)
347d9306527SDavid du Colombier return nil;
348d9306527SDavid du Colombier
349*3be74836SDavid du Colombier mc = metachunks(mb);
350d9306527SDavid du Colombier
351d9306527SDavid du Colombier /* look for hole */
352d9306527SDavid du Colombier o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
353d9306527SDavid du Colombier for(i=0; i<mb->nindex; i++) {
354d9306527SDavid du Colombier if(mc[i].offset - o >= n) {
355*3be74836SDavid du Colombier vtfree(mc);
356d9306527SDavid du Colombier return mb->buf + o;
357d9306527SDavid du Colombier }
358d9306527SDavid du Colombier o = mc[i].offset + mc[i].size;
359d9306527SDavid du Colombier }
360d9306527SDavid du Colombier
361d9306527SDavid du Colombier if(mb->maxsize - o >= n) {
362*3be74836SDavid du Colombier vtfree(mc);
363d9306527SDavid du Colombier return mb->buf + o;
364d9306527SDavid du Colombier }
365d9306527SDavid du Colombier
366d9306527SDavid du Colombier /* compact and return off the end */
367*3be74836SDavid du Colombier mbcompact(mb, mc);
368*3be74836SDavid du Colombier vtfree(mc);
369d9306527SDavid du Colombier
370d9306527SDavid du Colombier assert(mb->maxsize - mb->size >= n);
371d9306527SDavid du Colombier return mb->buf + mb->size;
372d9306527SDavid du Colombier }
373d9306527SDavid du Colombier
374d9306527SDavid du Colombier int
vdsize(VacDir * dir,int version)375*3be74836SDavid du Colombier vdsize(VacDir *dir, int version)
376d9306527SDavid du Colombier {
377d9306527SDavid du Colombier int n;
378d9306527SDavid du Colombier
379*3be74836SDavid du Colombier if(version < 8 || version > 9)
380*3be74836SDavid du Colombier sysfatal("bad version %d in vdpack", version);
38149223a73SDavid du Colombier
382*3be74836SDavid du Colombier /* constant part */
383d9306527SDavid du Colombier n = 4 + /* magic */
384d9306527SDavid du Colombier 2 + /* version */
385d9306527SDavid du Colombier 4 + /* entry */
386d9306527SDavid du Colombier 8 + /* qid */
387d9306527SDavid du Colombier 4 + /* mtime */
388d9306527SDavid du Colombier 4 + /* mcount */
389d9306527SDavid du Colombier 4 + /* ctime */
390d9306527SDavid du Colombier 4 + /* atime */
391d9306527SDavid du Colombier 4 + /* mode */
392d9306527SDavid du Colombier 0;
393d9306527SDavid du Colombier
394*3be74836SDavid du Colombier if(version == 9){
395*3be74836SDavid du Colombier n += 4 + /* gen */
396*3be74836SDavid du Colombier 4 + /* mentry */
397*3be74836SDavid du Colombier 4 + /* mgen */
398*3be74836SDavid du Colombier 0;
399*3be74836SDavid du Colombier }
400*3be74836SDavid du Colombier
401d9306527SDavid du Colombier /* strings */
402d9306527SDavid du Colombier n += 2 + strlen(dir->elem);
403d9306527SDavid du Colombier n += 2 + strlen(dir->uid);
404d9306527SDavid du Colombier n += 2 + strlen(dir->gid);
405d9306527SDavid du Colombier n += 2 + strlen(dir->mid);
406d9306527SDavid du Colombier
407d9306527SDavid du Colombier /* optional sections */
408*3be74836SDavid du Colombier if(version < 9 && dir->plan9) {
409d9306527SDavid du Colombier n += 3 + /* option header */
410*3be74836SDavid du Colombier 8 + /* path */
411*3be74836SDavid du Colombier 4; /* version */
412*3be74836SDavid du Colombier }
413*3be74836SDavid du Colombier if(dir->qidspace) {
414*3be74836SDavid du Colombier n += 3 + /* option header */
415*3be74836SDavid du Colombier 8 + /* qid offset */
416*3be74836SDavid du Colombier 8; /* qid max */
417*3be74836SDavid du Colombier }
418*3be74836SDavid du Colombier if(version < 9 && dir->gen) {
419*3be74836SDavid du Colombier n += 3 + /* option header */
420*3be74836SDavid du Colombier 4; /* gen */
421d9306527SDavid du Colombier }
422d9306527SDavid du Colombier
423d9306527SDavid du Colombier return n;
424d9306527SDavid du Colombier }
425d9306527SDavid du Colombier
426d9306527SDavid du Colombier void
vdpack(VacDir * dir,MetaEntry * me,int version)427*3be74836SDavid du Colombier vdpack(VacDir *dir, MetaEntry *me, int version)
428d9306527SDavid du Colombier {
429d9306527SDavid du Colombier uchar *p;
430d9306527SDavid du Colombier ulong t32;
431d9306527SDavid du Colombier
432*3be74836SDavid du Colombier if(version < 8 || version > 9)
433*3be74836SDavid du Colombier sysfatal("bad version %d in vdpack", version);
434*3be74836SDavid du Colombier
435d9306527SDavid du Colombier p = me->p;
436d9306527SDavid du Colombier
437d9306527SDavid du Colombier U32PUT(p, DirMagic);
438*3be74836SDavid du Colombier U16PUT(p+4, version); /* version */
439d9306527SDavid du Colombier p += 6;
440d9306527SDavid du Colombier
441*3be74836SDavid du Colombier p += stringpack(dir->elem, p);
442d9306527SDavid du Colombier
443d9306527SDavid du Colombier U32PUT(p, dir->entry);
444*3be74836SDavid du Colombier p += 4;
445d9306527SDavid du Colombier
446*3be74836SDavid du Colombier if(version == 9){
447*3be74836SDavid du Colombier U32PUT(p, dir->gen);
448*3be74836SDavid du Colombier U32PUT(p+4, dir->mentry);
449*3be74836SDavid du Colombier U32PUT(p+8, dir->mgen);
450*3be74836SDavid du Colombier p += 12;
451*3be74836SDavid du Colombier }
452*3be74836SDavid du Colombier
453*3be74836SDavid du Colombier U64PUT(p, dir->qid, t32);
454*3be74836SDavid du Colombier p += 8;
455*3be74836SDavid du Colombier
456*3be74836SDavid du Colombier p += stringpack(dir->uid, p);
457*3be74836SDavid du Colombier p += stringpack(dir->gid, p);
458*3be74836SDavid du Colombier p += stringpack(dir->mid, p);
459d9306527SDavid du Colombier
460d9306527SDavid du Colombier U32PUT(p, dir->mtime);
461d9306527SDavid du Colombier U32PUT(p+4, dir->mcount);
462d9306527SDavid du Colombier U32PUT(p+8, dir->ctime);
463d9306527SDavid du Colombier U32PUT(p+12, dir->atime);
464d9306527SDavid du Colombier U32PUT(p+16, dir->mode);
465d9306527SDavid du Colombier p += 5*4;
466d9306527SDavid du Colombier
467*3be74836SDavid du Colombier if(dir->plan9 && version < 9) {
468*3be74836SDavid du Colombier U8PUT(p, DirPlan9Entry);
469*3be74836SDavid du Colombier U16PUT(p+1, 8+4);
470*3be74836SDavid du Colombier p += 3;
471*3be74836SDavid du Colombier U64PUT(p, dir->p9path, t32);
472*3be74836SDavid du Colombier U32PUT(p+8, dir->p9version);
473*3be74836SDavid du Colombier p += 12;
474*3be74836SDavid du Colombier }
475*3be74836SDavid du Colombier
476*3be74836SDavid du Colombier if(dir->qidspace) {
477d9306527SDavid du Colombier U8PUT(p, DirQidSpaceEntry);
478d9306527SDavid du Colombier U16PUT(p+1, 2*8);
479d9306527SDavid du Colombier p += 3;
480*3be74836SDavid du Colombier U64PUT(p, dir->qidoffset, t32);
481*3be74836SDavid du Colombier U64PUT(p+8, dir->qidmax, t32);
482*3be74836SDavid du Colombier p += 16;
483*3be74836SDavid du Colombier }
484*3be74836SDavid du Colombier
485*3be74836SDavid du Colombier if(dir->gen && version < 9) {
486*3be74836SDavid du Colombier U8PUT(p, DirGenEntry);
487*3be74836SDavid du Colombier U16PUT(p+1, 4);
488*3be74836SDavid du Colombier p += 3;
489*3be74836SDavid du Colombier U32PUT(p, dir->gen);
490*3be74836SDavid du Colombier p += 4;
491d9306527SDavid du Colombier }
492d9306527SDavid du Colombier
493d9306527SDavid du Colombier assert(p == me->p + me->size);
494d9306527SDavid du Colombier }
495d9306527SDavid du Colombier
496d9306527SDavid du Colombier int
vdunpack(VacDir * dir,MetaEntry * me)497*3be74836SDavid du Colombier vdunpack(VacDir *dir, MetaEntry *me)
498d9306527SDavid du Colombier {
499d9306527SDavid du Colombier int t, nn, n, version;
500d9306527SDavid du Colombier uchar *p;
501d9306527SDavid du Colombier
502d9306527SDavid du Colombier p = me->p;
503d9306527SDavid du Colombier n = me->size;
504d9306527SDavid du Colombier
505d9306527SDavid du Colombier memset(dir, 0, sizeof(VacDir));
506d9306527SDavid du Colombier
507d9306527SDavid du Colombier /* magic */
508d9306527SDavid du Colombier if(n < 4 || U32GET(p) != DirMagic)
509d9306527SDavid du Colombier goto Err;
510d9306527SDavid du Colombier p += 4;
511d9306527SDavid du Colombier n -= 4;
512d9306527SDavid du Colombier
513d9306527SDavid du Colombier /* version */
514d9306527SDavid du Colombier if(n < 2)
515d9306527SDavid du Colombier goto Err;
516d9306527SDavid du Colombier version = U16GET(p);
517d9306527SDavid du Colombier if(version < 7 || version > 9)
518d9306527SDavid du Colombier goto Err;
519d9306527SDavid du Colombier p += 2;
520d9306527SDavid du Colombier n -= 2;
521d9306527SDavid du Colombier
522d9306527SDavid du Colombier /* elem */
523*3be74836SDavid du Colombier if(stringunpack(&dir->elem, &p, &n) < 0)
524d9306527SDavid du Colombier goto Err;
525d9306527SDavid du Colombier
526d9306527SDavid du Colombier /* entry */
527d9306527SDavid du Colombier if(n < 4)
528d9306527SDavid du Colombier goto Err;
529d9306527SDavid du Colombier dir->entry = U32GET(p);
530d9306527SDavid du Colombier p += 4;
531d9306527SDavid du Colombier n -= 4;
532d9306527SDavid du Colombier
533d9306527SDavid du Colombier if(version < 9) {
534d9306527SDavid du Colombier dir->gen = 0;
535d9306527SDavid du Colombier dir->mentry = dir->entry+1;
536d9306527SDavid du Colombier dir->mgen = 0;
537d9306527SDavid du Colombier } else {
538d9306527SDavid du Colombier if(n < 3*4)
539d9306527SDavid du Colombier goto Err;
540d9306527SDavid du Colombier dir->gen = U32GET(p);
541d9306527SDavid du Colombier dir->mentry = U32GET(p+4);
542d9306527SDavid du Colombier dir->mgen = U32GET(p+8);
543d9306527SDavid du Colombier p += 3*4;
544d9306527SDavid du Colombier n -= 3*4;
545d9306527SDavid du Colombier }
546d9306527SDavid du Colombier
547d9306527SDavid du Colombier /* size is gotten from DirEntry */
548d9306527SDavid du Colombier
549d9306527SDavid du Colombier /* qid */
550d9306527SDavid du Colombier if(n < 8)
551d9306527SDavid du Colombier goto Err;
552d9306527SDavid du Colombier dir->qid = U64GET(p);
553d9306527SDavid du Colombier p += 8;
554d9306527SDavid du Colombier n -= 8;
555d9306527SDavid du Colombier
556d9306527SDavid du Colombier /* skip replacement */
557d9306527SDavid du Colombier if(version == 7) {
558d9306527SDavid du Colombier if(n < VtScoreSize)
559d9306527SDavid du Colombier goto Err;
560d9306527SDavid du Colombier p += VtScoreSize;
561d9306527SDavid du Colombier n -= VtScoreSize;
562d9306527SDavid du Colombier }
563d9306527SDavid du Colombier
564d9306527SDavid du Colombier /* uid */
565*3be74836SDavid du Colombier if(stringunpack(&dir->uid, &p, &n) < 0)
566d9306527SDavid du Colombier goto Err;
567d9306527SDavid du Colombier
568d9306527SDavid du Colombier /* gid */
569*3be74836SDavid du Colombier if(stringunpack(&dir->gid, &p, &n) < 0)
570d9306527SDavid du Colombier goto Err;
571d9306527SDavid du Colombier
572d9306527SDavid du Colombier /* mid */
573*3be74836SDavid du Colombier if(stringunpack(&dir->mid, &p, &n) < 0)
574d9306527SDavid du Colombier goto Err;
575d9306527SDavid du Colombier
576d9306527SDavid du Colombier if(n < 5*4)
577d9306527SDavid du Colombier goto Err;
578d9306527SDavid du Colombier dir->mtime = U32GET(p);
579d9306527SDavid du Colombier dir->mcount = U32GET(p+4);
580d9306527SDavid du Colombier dir->ctime = U32GET(p+8);
581d9306527SDavid du Colombier dir->atime = U32GET(p+12);
582d9306527SDavid du Colombier dir->mode = U32GET(p+16);
583d9306527SDavid du Colombier p += 5*4;
584d9306527SDavid du Colombier n -= 5*4;
585d9306527SDavid du Colombier
586d9306527SDavid du Colombier /* optional meta data */
587d9306527SDavid du Colombier while(n > 0) {
588d9306527SDavid du Colombier if(n < 3)
589d9306527SDavid du Colombier goto Err;
590d9306527SDavid du Colombier t = p[0];
591d9306527SDavid du Colombier nn = U16GET(p+1);
592d9306527SDavid du Colombier p += 3;
593d9306527SDavid du Colombier n -= 3;
594d9306527SDavid du Colombier if(n < nn)
595d9306527SDavid du Colombier goto Err;
596d9306527SDavid du Colombier switch(t) {
597d9306527SDavid du Colombier case DirPlan9Entry:
598d9306527SDavid du Colombier /* not valid in version >= 9 */
599d9306527SDavid du Colombier if(version >= 9)
600d9306527SDavid du Colombier break;
601d9306527SDavid du Colombier if(dir->plan9 || nn != 12)
602d9306527SDavid du Colombier goto Err;
603d9306527SDavid du Colombier dir->plan9 = 1;
604d9306527SDavid du Colombier dir->p9path = U64GET(p);
605d9306527SDavid du Colombier dir->p9version = U32GET(p+8);
606d9306527SDavid du Colombier if(dir->mcount == 0)
607d9306527SDavid du Colombier dir->mcount = dir->p9version;
608d9306527SDavid du Colombier break;
609d9306527SDavid du Colombier case DirGenEntry:
610d9306527SDavid du Colombier /* not valid in version >= 9 */
611d9306527SDavid du Colombier if(version >= 9)
612d9306527SDavid du Colombier break;
613d9306527SDavid du Colombier break;
614d9306527SDavid du Colombier case DirQidSpaceEntry:
615*3be74836SDavid du Colombier if(dir->qidspace || nn != 16)
616d9306527SDavid du Colombier goto Err;
617*3be74836SDavid du Colombier dir->qidspace = 1;
618*3be74836SDavid du Colombier dir->qidoffset = U64GET(p);
619*3be74836SDavid du Colombier dir->qidmax = U64GET(p+8);
620d9306527SDavid du Colombier break;
621d9306527SDavid du Colombier }
622d9306527SDavid du Colombier p += nn;
623d9306527SDavid du Colombier n -= nn;
624d9306527SDavid du Colombier }
625d9306527SDavid du Colombier
626d9306527SDavid du Colombier if(p != me->p + me->size)
627d9306527SDavid du Colombier goto Err;
628d9306527SDavid du Colombier
629e538c934SDavid du Colombier return 0;
630*3be74836SDavid du Colombier Err:
631*3be74836SDavid du Colombier werrstr(EBadMeta);
632*3be74836SDavid du Colombier vdcleanup(dir);
633*3be74836SDavid du Colombier return -1;
634*3be74836SDavid du Colombier }
635*3be74836SDavid du Colombier
636*3be74836SDavid du Colombier void
vdcleanup(VacDir * dir)637*3be74836SDavid du Colombier vdcleanup(VacDir *dir)
638*3be74836SDavid du Colombier {
639*3be74836SDavid du Colombier vtfree(dir->elem);
640*3be74836SDavid du Colombier dir->elem = nil;
641*3be74836SDavid du Colombier vtfree(dir->uid);
642*3be74836SDavid du Colombier dir->uid = nil;
643*3be74836SDavid du Colombier vtfree(dir->gid);
644*3be74836SDavid du Colombier dir->gid = nil;
645*3be74836SDavid du Colombier vtfree(dir->mid);
646*3be74836SDavid du Colombier dir->mid = nil;
647*3be74836SDavid du Colombier }
648*3be74836SDavid du Colombier
649*3be74836SDavid du Colombier void
vdcopy(VacDir * dst,VacDir * src)650*3be74836SDavid du Colombier vdcopy(VacDir *dst, VacDir *src)
651*3be74836SDavid du Colombier {
652*3be74836SDavid du Colombier *dst = *src;
653*3be74836SDavid du Colombier dst->elem = vtstrdup(dst->elem);
654*3be74836SDavid du Colombier dst->uid = vtstrdup(dst->uid);
655*3be74836SDavid du Colombier dst->gid = vtstrdup(dst->gid);
656*3be74836SDavid du Colombier dst->mid = vtstrdup(dst->mid);
657*3be74836SDavid du Colombier }
658*3be74836SDavid du Colombier
659*3be74836SDavid du Colombier int
mbsearch(MetaBlock * mb,char * elem,int * ri,MetaEntry * me)660*3be74836SDavid du Colombier mbsearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
661*3be74836SDavid du Colombier {
662*3be74836SDavid du Colombier int i;
663*3be74836SDavid du Colombier int b, t, x;
664*3be74836SDavid du Colombier
665*3be74836SDavid du Colombier /* binary search within block */
666*3be74836SDavid du Colombier b = 0;
667*3be74836SDavid du Colombier t = mb->nindex;
668*3be74836SDavid du Colombier while(b < t) {
669*3be74836SDavid du Colombier i = (b+t)>>1;
670*3be74836SDavid du Colombier if(meunpack(me, mb, i) < 0)
671*3be74836SDavid du Colombier return 0;
672*3be74836SDavid du Colombier if(mb->unbotch)
673*3be74836SDavid du Colombier x = mecmpnew(me, elem);
674*3be74836SDavid du Colombier else
675*3be74836SDavid du Colombier x = mecmp(me, elem);
676*3be74836SDavid du Colombier
677*3be74836SDavid du Colombier if(x == 0) {
678*3be74836SDavid du Colombier *ri = i;
679*3be74836SDavid du Colombier return 1;
680*3be74836SDavid du Colombier }
681*3be74836SDavid du Colombier
682*3be74836SDavid du Colombier if(x < 0)
683*3be74836SDavid du Colombier b = i+1;
684*3be74836SDavid du Colombier else /* x > 0 */
685*3be74836SDavid du Colombier t = i;
686*3be74836SDavid du Colombier }
687*3be74836SDavid du Colombier
688*3be74836SDavid du Colombier assert(b == t);
689*3be74836SDavid du Colombier
690*3be74836SDavid du Colombier *ri = b; /* b is the index to insert this entry */
691*3be74836SDavid du Colombier memset(me, 0, sizeof(*me));
692*3be74836SDavid du Colombier
693*3be74836SDavid du Colombier return -1;
694*3be74836SDavid du Colombier }
695*3be74836SDavid du Colombier
696*3be74836SDavid du Colombier void
mbinit(MetaBlock * mb,uchar * p,int n,int entries)697*3be74836SDavid du Colombier mbinit(MetaBlock *mb, uchar *p, int n, int entries)
698*3be74836SDavid du Colombier {
699*3be74836SDavid du Colombier memset(mb, 0, sizeof(MetaBlock));
700*3be74836SDavid du Colombier mb->maxsize = n;
701*3be74836SDavid du Colombier mb->buf = p;
702*3be74836SDavid du Colombier mb->maxindex = entries;
703*3be74836SDavid du Colombier mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
704*3be74836SDavid du Colombier }
705*3be74836SDavid du Colombier
706*3be74836SDavid du Colombier int
mbresize(MetaBlock * mb,MetaEntry * me,int n)707*3be74836SDavid du Colombier mbresize(MetaBlock *mb, MetaEntry *me, int n)
708*3be74836SDavid du Colombier {
709*3be74836SDavid du Colombier uchar *p, *ep;
710*3be74836SDavid du Colombier
711*3be74836SDavid du Colombier /* easy case */
712*3be74836SDavid du Colombier if(n <= me->size){
713*3be74836SDavid du Colombier me->size = n;
714*3be74836SDavid du Colombier return 0;
715*3be74836SDavid du Colombier }
716*3be74836SDavid du Colombier
717*3be74836SDavid du Colombier /* try and expand entry */
718*3be74836SDavid du Colombier
719*3be74836SDavid du Colombier p = me->p + me->size;
720*3be74836SDavid du Colombier ep = mb->buf + mb->maxsize;
721*3be74836SDavid du Colombier while(p < ep && *p == 0)
722*3be74836SDavid du Colombier p++;
723*3be74836SDavid du Colombier if(n <= p - me->p){
724*3be74836SDavid du Colombier me->size = n;
725*3be74836SDavid du Colombier return 0;
726*3be74836SDavid du Colombier }
727*3be74836SDavid du Colombier
728*3be74836SDavid du Colombier p = mballoc(mb, n);
729*3be74836SDavid du Colombier if(p != nil){
730*3be74836SDavid du Colombier me->p = p;
731*3be74836SDavid du Colombier me->size = n;
732*3be74836SDavid du Colombier return 0;
733*3be74836SDavid du Colombier }
734*3be74836SDavid du Colombier
735*3be74836SDavid du Colombier return -1;
736e538c934SDavid du Colombier }
737