3 typedef struct MetaChunk MetaChunk;
11 static int stringUnpack(char **s, uchar **p, int *n);
12 static int meCmp(MetaEntry*, char *s);
13 static int meCmpOld(MetaEntry*, char *s);
17 static char EBadMeta[] = "corrupted meta data";
18 static char ENoFile[] = "file does not exist";
21 * integer conversion routines
23 #define U8GET(p) ((p)[0])
24 #define U16GET(p) (((p)[0]<<8)|(p)[1])
25 #define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
26 #define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
27 #define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
29 #define U8PUT(p,v) (p)[0]=(v)
30 #define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v)
31 #define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
32 #define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
33 #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
36 stringUnpack(char **s, uchar **p, int *n)
57 stringPack(char *s, uchar *p)
68 mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
72 if(0)fprint(2, "mbSearch %s\n", elem);
74 /* binary search within block */
82 x = meCmpOld(me, elem);
99 *ri = b; /* b is the index to insert this entry */
100 memset(me, 0, sizeof(*me));
107 mbInit(MetaBlock *mb, uchar *p, int n, int ne)
114 mb->size = MetaHeaderSize + ne*MetaIndexSize;
120 mbUnpack(MetaBlock *mb, uchar *p, int n)
131 memset(mb, 0, sizeof(MetaBlock));
136 if(magic != MetaMagic && magic != MetaMagic-1)
138 mb->size = U16GET(p+4);
139 mb->free = U16GET(p+6);
140 mb->maxindex = U16GET(p+8);
141 mb->nindex = U16GET(p+10);
142 mb->botch = magic != MetaMagic;
146 omin = MetaHeaderSize + mb->maxindex*MetaIndexSize;
153 /* check the index table - ensures that meUnpack and meCmp never fail */
154 for(i=0; i<mb->nindex; i++){
157 if(eo < omin || eo+en > mb->size || en < 8)
160 if(U32GET(q) != DirMagic)
173 mbPack(MetaBlock *mb)
181 U32PUT(p, MetaMagic);
182 U16PUT(p+4, mb->size);
183 U16PUT(p+6, mb->free);
184 U16PUT(p+8, mb->maxindex);
185 U16PUT(p+10, mb->nindex);
190 mbDelete(MetaBlock *mb, int i)
196 assert(i < mb->nindex);
197 meUnpack(&me, mb, i);
198 memset(me.p, 0, me.size);
200 if(me.p - mb->buf + me.size == mb->size)
205 p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
206 n = (mb->nindex-i-1)*MetaIndexSize;
207 memmove(p, p+MetaIndexSize, n);
208 memset(p+n, 0, MetaIndexSize);
213 mbInsert(MetaBlock *mb, int i, MetaEntry *me)
218 assert(mb->nindex < mb->maxindex);
223 mb->free -= mb->size - o;
228 p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
229 n = (mb->nindex-i)*MetaIndexSize;
230 memmove(p+MetaIndexSize, p, n);
231 U16PUT(p, me->p - mb->buf);
232 U16PUT(p+2, me->size);
237 mbResize(MetaBlock *mb, MetaEntry *me, int n)
247 /* try and expand entry */
249 p = me->p + me->size;
250 ep = mb->buf + mb->maxsize;
251 while(p < ep && *p == 0)
269 meUnpack(MetaEntry *me, MetaBlock *mb, int i)
274 assert(i >= 0 && i < mb->nindex);
276 p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
280 me->p = mb->buf + eo;
283 /* checked by mbUnpack */
284 assert(me->size >= 8);
287 /* assumes a small amount of checking has been done in mbEntry */
289 meCmp(MetaEntry *me, char *s)
296 /* skip magic & version */
319 * This is the old and broken meCmp.
320 * This cmp routine reverse the sense of the comparison
321 * when one string is a prefix of the other.
322 * In other words, it put "ab" after "abc" rather
323 * than before. This behaviour is ok; binary search
324 * and sort still work. However, it is goes against
325 * the usual convention.
328 meCmpOld(MetaEntry *me, char *s)
335 /* skip magic & version */
358 offsetCmp(const void *s0, const void *s1)
360 MetaChunk *mc0, *mc1;
362 mc0 = (MetaChunk*)s0;
363 mc1 = (MetaChunk*)s1;
364 if(mc0->offset < mc1->offset)
366 if(mc0->offset > mc1->offset)
372 metaChunks(MetaBlock *mb)
378 mc = vtmalloc(mb->nindex*sizeof(MetaChunk));
379 p = mb->buf + MetaHeaderSize;
380 for(i = 0; i<mb->nindex; i++){
381 mc[i].offset = U16GET(p);
382 mc[i].size = U16GET(p+2);
387 qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
389 /* check block looks ok */
390 oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
393 for(i=0; i<mb->nindex; i++){
402 if(mb->size - oo != mb->free)
407 fprint(2, "metaChunks failed!\n");
408 oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
409 for(i=0; i<mb->nindex; i++){
410 fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size);
413 fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo);
420 mbCompact(MetaBlock *mb, MetaChunk *mc)
424 oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
426 for(i=0; i<mb->nindex; i++){
430 memmove(mb->buf + oo, mb->buf + o, n);
431 U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
441 mbAlloc(MetaBlock *mb, int n)
447 if(mb->maxsize - mb->size >= n)
448 return mb->buf + mb->size;
450 /* check if possible */
451 if(mb->maxsize - mb->size + mb->free < n)
456 fprint(2, "mbAlloc: metaChunks failed: %r\n");
461 o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
462 for(i=0; i<mb->nindex; i++){
463 if(mc[i].offset - o >= n){
467 o = mc[i].offset + mc[i].size;
470 if(mb->maxsize - o >= n){
475 /* compact and return off the end */
479 if(mb->maxsize - mb->size < n){
483 return mb->buf + mb->size;
487 deSize(DirEntry *dir)
508 n += 2 + strlen(dir->elem);
509 n += 2 + strlen(dir->uid);
510 n += 2 + strlen(dir->gid);
511 n += 2 + strlen(dir->mid);
513 /* optional sections */
515 n += 3 + /* option header */
524 dePack(DirEntry *dir, MetaEntry *me)
532 U16PUT(p+4, 9); /* version */
535 p += stringPack(dir->elem, p);
537 U32PUT(p, dir->entry);
538 U32PUT(p+4, dir->gen);
539 U32PUT(p+8, dir->mentry);
540 U32PUT(p+12, dir->mgen);
541 U64PUT(p+16, dir->qid, t32);
544 p += stringPack(dir->uid, p);
545 p += stringPack(dir->gid, p);
546 p += stringPack(dir->mid, p);
548 U32PUT(p, dir->mtime);
549 U32PUT(p+4, dir->mcount);
550 U32PUT(p+8, dir->ctime);
551 U32PUT(p+12, dir->atime);
552 U32PUT(p+16, dir->mode);
556 U8PUT(p, DeQidSpace);
559 U64PUT(p, dir->qidOffset, t32);
560 U64PUT(p+8, dir->qidMax, t32);
564 assert(p == me->p + me->size);
569 deUnpack(DirEntry *dir, MetaEntry *me)
571 int t, nn, n, version;
577 memset(dir, 0, sizeof(DirEntry));
579 if(0)print("deUnpack\n");
581 if(n < 4 || U32GET(p) != DirMagic)
586 if(0)print("deUnpack: got magic\n");
591 if(version < 7 || version > 9)
596 if(0)print("deUnpack: got version\n");
599 if(!stringUnpack(&dir->elem, &p, &n))
602 if(0)print("deUnpack: got elem\n");
607 dir->entry = U32GET(p);
611 if(0)print("deUnpack: got entry\n");
615 dir->mentry = dir->entry+1;
620 dir->gen = U32GET(p);
621 dir->mentry = U32GET(p+4);
622 dir->mgen = U32GET(p+8);
627 if(0)print("deUnpack: got gen etc\n");
629 /* size is gotten from VtEntry */
635 dir->qid = U64GET(p);
639 if(0)print("deUnpack: got qid\n");
640 /* skip replacement */
649 if(!stringUnpack(&dir->uid, &p, &n))
653 if(!stringUnpack(&dir->gid, &p, &n))
657 if(!stringUnpack(&dir->mid, &p, &n))
660 if(0)print("deUnpack: got ids\n");
663 dir->mtime = U32GET(p);
664 dir->mcount = U32GET(p+4);
665 dir->ctime = U32GET(p+8);
666 dir->atime = U32GET(p+12);
667 dir->mode = U32GET(p+16);
671 if(0)print("deUnpack: got times\n");
672 /* optional meta data */
684 /* not valid in version >= 9 */
687 if(dir->plan9 || nn != 12)
690 dir->p9path = U64GET(p);
691 dir->p9version = U32GET(p+8);
693 dir->mcount = dir->p9version;
696 /* not valid in version >= 9 */
701 if(dir->qidSpace || nn != 16)
704 dir->qidOffset = U64GET(p);
705 dir->qidMax = U64GET(p+8);
711 if(0)print("deUnpack: got options\n");
713 if(p != me->p + me->size)
716 if(0)print("deUnpack: correct size\n");
719 if(0)print("deUnpack: XXXXXXXXXXXX EBadMeta\n");
726 deCleanup(DirEntry *dir)
739 deCopy(DirEntry *dst, DirEntry *src)
742 dst->elem = vtstrdup(src->elem);
743 dst->uid = vtstrdup(src->uid);
744 dst->gid = vtstrdup(src->gid);
745 dst->mid = vtstrdup(src->mid);