7 typedef struct MetaChunk MetaChunk;
15 static int stringUnpack(char **s, uchar **p, int *n);
18 * integer conversion routines
20 #define U8GET(p) ((p)[0])
21 #define U16GET(p) (((p)[0]<<8)|(p)[1])
22 #define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
23 #define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
24 #define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
26 #define U8PUT(p,v) (p)[0]=(v)
27 #define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v)
28 #define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v)
29 #define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
30 #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
33 stringUnpack(char **s, uchar **p, int *n)
45 *s = vtMemAlloc(nn+1);
54 stringPack(char *s, uchar *p)
66 mbUnpack(MetaBlock *mb, uchar *p, int n)
74 memset(mb, 0, sizeof(MetaBlock));
79 if(magic != MetaMagic && magic != MetaMagic+1) {
80 vtSetError("bad meta block magic");
83 mb->size = U16GET(p+4);
84 mb->free = U16GET(p+6);
85 mb->maxindex = U16GET(p+8);
86 mb->nindex = U16GET(p+10);
87 mb->unbotch = (magic == MetaMagic+1);
90 vtSetError("bad meta block size");
97 if(n < mb->maxindex*MetaIndexSize) {
98 vtSetError("truncated meta block 2");
105 mbPack(MetaBlock *mb)
111 U32PUT(p, MetaMagic);
112 U16PUT(p+4, mb->size);
113 U16PUT(p+6, mb->free);
114 U16PUT(p+8, mb->maxindex);
115 U16PUT(p+10, mb->nindex);
120 mbDelete(MetaBlock *mb, int i, MetaEntry *me)
125 assert(i < mb->nindex);
127 if(me->p - mb->buf + me->size == mb->size)
128 mb->size -= me->size;
130 mb->free += me->size;
132 p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
133 n = (mb->nindex-i-1)*MetaIndexSize;
134 memmove(p, p+MetaIndexSize, n);
135 memset(p+n, 0, MetaIndexSize);
140 mbInsert(MetaBlock *mb, int i, MetaEntry *me)
145 assert(mb->nindex < mb->maxindex);
150 mb->free -= mb->size - o;
155 p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
156 n = (mb->nindex-i)*MetaIndexSize;
157 memmove(p+MetaIndexSize, p, n);
158 U16PUT(p, me->p - mb->buf);
159 U16PUT(p+2, me->size);
164 meUnpack(MetaEntry *me, MetaBlock *mb, int i)
169 if(i < 0 || i >= mb->nindex) {
170 vtSetError("bad meta entry index");
174 p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
178 if(0)print("eo = %d en = %d\n", eo, en);
179 if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
180 vtSetError("corrupted entry in meta block");
184 if(eo+en > mb->size) {
185 vtSetError("truncated meta block");
191 /* make sure entry looks ok and includes an elem name */
192 if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
193 vtSetError("corrupted meta block entry");
203 /* assumes a small amount of checking has been done in mbEntry */
205 meCmp(MetaEntry *me, char *s)
216 assert(n + 8 < me->size);
233 meCmpNew(MetaEntry *me, char *s)
244 assert(n + 8 < me->size);
261 offsetCmp(void *s0, void *s1)
263 MetaChunk *mc0, *mc1;
267 if(mc0->offset < mc1->offset)
269 if(mc0->offset > mc1->offset)
275 metaChunks(MetaBlock *mb)
281 mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
282 p = mb->buf + MetaHeaderSize;
283 for(i = 0; i<mb->nindex; i++) {
284 mc[i].offset = U16GET(p);
285 mc[i].size = U16GET(p+2);
290 qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
292 /* check block looks ok */
293 oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
296 for(i=0; i<mb->nindex; i++) {
305 if(mb->size - oo != mb->free)
315 mbCompact(MetaBlock *mb, MetaChunk *mc)
319 oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
321 for(i=0; i<mb->nindex; i++) {
325 memmove(mb->buf + oo, mb->buf + o, n);
326 U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
336 mbAlloc(MetaBlock *mb, int n)
342 if(mb->maxsize - mb->size >= n)
343 return mb->buf + mb->size;
345 /* check if possible */
346 if(mb->maxsize - mb->size + mb->free < n)
352 o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
353 for(i=0; i<mb->nindex; i++) {
354 if(mc[i].offset - o >= n) {
358 o = mc[i].offset + mc[i].size;
361 if(mb->maxsize - o >= n) {
366 /* compact and return off the end */
370 assert(mb->maxsize - mb->size >= n);
371 return mb->buf + mb->size;
396 n += 2 + strlen(dir->elem);
397 n += 2 + strlen(dir->uid);
398 n += 2 + strlen(dir->gid);
399 n += 2 + strlen(dir->mid);
401 /* optional sections */
403 n += 3 + /* option header */
412 vdPack(VacDir *dir, MetaEntry *me)
420 U16PUT(p+4, 9); /* version */
423 p += stringPack(dir->elem, p);
425 U32PUT(p, dir->entry);
426 U32PUT(p+4, dir->gen);
427 U32PUT(p+8, dir->mentry);
428 U32PUT(p+12, dir->mgen);
429 U64PUT(p+16, dir->qid, t32);
432 p += stringPack(dir->uid, p);
433 p += stringPack(dir->gid, p);
434 p += stringPack(dir->mid, p);
436 U32PUT(p, dir->mtime);
437 U32PUT(p+4, dir->mcount);
438 U32PUT(p+8, dir->ctime);
439 U32PUT(p+12, dir->atime);
440 U32PUT(p+16, dir->mode);
444 U8PUT(p, DirQidSpaceEntry);
447 U64PUT(p, dir->qidOffset, t32);
448 U64PUT(p+8, dir->qidMax, t32);
451 assert(p == me->p + me->size);
456 vdUnpack(VacDir *dir, MetaEntry *me)
458 int t, nn, n, version;
464 memset(dir, 0, sizeof(VacDir));
466 if(0)print("vdUnpack\n");
468 if(n < 4 || U32GET(p) != DirMagic)
473 if(0)print("vdUnpack: got magic\n");
478 if(version < 7 || version > 9)
483 if(0)print("vdUnpack: got version\n");
486 if(!stringUnpack(&dir->elem, &p, &n))
489 if(0)print("vdUnpack: got elem\n");
494 dir->entry = U32GET(p);
498 if(0)print("vdUnpack: got entry\n");
502 dir->mentry = dir->entry+1;
507 dir->gen = U32GET(p);
508 dir->mentry = U32GET(p+4);
509 dir->mgen = U32GET(p+8);
514 if(0)print("vdUnpack: got gen etc\n");
516 /* size is gotten from DirEntry */
521 dir->qid = U64GET(p);
525 if(0)print("vdUnpack: got qid\n");
526 /* skip replacement */
535 if(!stringUnpack(&dir->uid, &p, &n))
539 if(!stringUnpack(&dir->gid, &p, &n))
543 if(!stringUnpack(&dir->mid, &p, &n))
546 if(0)print("vdUnpack: got ids\n");
549 dir->mtime = U32GET(p);
550 dir->mcount = U32GET(p+4);
551 dir->ctime = U32GET(p+8);
552 dir->atime = U32GET(p+12);
553 dir->mode = U32GET(p+16);
557 if(0)print("vdUnpack: got times\n");
558 /* optional meta data */
570 /* not valid in version >= 9 */
573 if(dir->plan9 || nn != 12)
576 dir->p9path = U64GET(p);
577 dir->p9version = U32GET(p+8);
579 dir->mcount = dir->p9version;
582 /* not valid in version >= 9 */
586 case DirQidSpaceEntry:
587 if(dir->qidSpace || nn != 16)
590 dir->qidOffset = U64GET(p);
591 dir->qidMax = U64GET(p+8);
597 if(0)print("vdUnpack: got options\n");
599 if(p != me->p + me->size)
602 if(0)print("vdUnpack: correct size\n");
605 if(0)print("vdUnpack: XXXXXXXXXXXX EbadMeta\n");
606 vtSetError(EBadMeta);