15e96a66cSDavid du Colombier #include "stdinc.h"
25e96a66cSDavid du Colombier
35e96a66cSDavid du Colombier typedef struct MetaChunk MetaChunk;
45e96a66cSDavid du Colombier
55e96a66cSDavid du Colombier struct MetaChunk {
65e96a66cSDavid du Colombier ushort offset;
75e96a66cSDavid du Colombier ushort size;
85e96a66cSDavid du Colombier ushort index;
95e96a66cSDavid du Colombier };
105e96a66cSDavid du Colombier
115e96a66cSDavid du Colombier static int stringUnpack(char **s, uchar **p, int *n);
125e96a66cSDavid du Colombier static int meCmp(MetaEntry*, char *s);
135e96a66cSDavid du Colombier static int meCmpOld(MetaEntry*, char *s);
145e96a66cSDavid du Colombier
155e96a66cSDavid du Colombier
165e96a66cSDavid du Colombier
175e96a66cSDavid du Colombier static char EBadMeta[] = "corrupted meta data";
185e96a66cSDavid du Colombier static char ENoFile[] = "file does not exist";
195e96a66cSDavid du Colombier
205e96a66cSDavid du Colombier /*
215e96a66cSDavid du Colombier * integer conversion routines
225e96a66cSDavid du Colombier */
235e96a66cSDavid du Colombier #define U8GET(p) ((p)[0])
245e96a66cSDavid du Colombier #define U16GET(p) (((p)[0]<<8)|(p)[1])
255e96a66cSDavid du Colombier #define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
265e96a66cSDavid du Colombier #define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
275e96a66cSDavid du Colombier #define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
285e96a66cSDavid du Colombier
295e96a66cSDavid du Colombier #define U8PUT(p,v) (p)[0]=(v)
305e96a66cSDavid du Colombier #define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v)
315e96a66cSDavid du Colombier #define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v)
325e96a66cSDavid du Colombier #define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
335e96a66cSDavid du Colombier #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
345e96a66cSDavid du Colombier
355e96a66cSDavid du Colombier static int
stringUnpack(char ** s,uchar ** p,int * n)365e96a66cSDavid du Colombier stringUnpack(char **s, uchar **p, int *n)
375e96a66cSDavid du Colombier {
385e96a66cSDavid du Colombier int nn;
395e96a66cSDavid du Colombier
405e96a66cSDavid du Colombier if(*n < 2)
415e96a66cSDavid du Colombier return 0;
425e96a66cSDavid du Colombier
435e96a66cSDavid du Colombier nn = U16GET(*p);
445e96a66cSDavid du Colombier *p += 2;
455e96a66cSDavid du Colombier *n -= 2;
465e96a66cSDavid du Colombier if(nn > *n)
475e96a66cSDavid du Colombier return 0;
485e96a66cSDavid du Colombier *s = vtMemAlloc(nn+1);
495e96a66cSDavid du Colombier memmove(*s, *p, nn);
505e96a66cSDavid du Colombier (*s)[nn] = 0;
515e96a66cSDavid du Colombier *p += nn;
525e96a66cSDavid du Colombier *n -= nn;
535e96a66cSDavid du Colombier return 1;
545e96a66cSDavid du Colombier }
555e96a66cSDavid du Colombier
565e96a66cSDavid du Colombier static int
stringPack(char * s,uchar * p)575e96a66cSDavid du Colombier stringPack(char *s, uchar *p)
585e96a66cSDavid du Colombier {
595e96a66cSDavid du Colombier int n;
605e96a66cSDavid du Colombier
615e96a66cSDavid du Colombier n = strlen(s);
625e96a66cSDavid du Colombier U16PUT(p, n);
635e96a66cSDavid du Colombier memmove(p+2, s, n);
645e96a66cSDavid du Colombier return n+2;
655e96a66cSDavid du Colombier }
665e96a66cSDavid du Colombier
675e96a66cSDavid du Colombier int
mbSearch(MetaBlock * mb,char * elem,int * ri,MetaEntry * me)685e96a66cSDavid du Colombier mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
695e96a66cSDavid du Colombier {
705e96a66cSDavid du Colombier int i;
715e96a66cSDavid du Colombier int b, t, x;
725e96a66cSDavid du Colombier if(0)fprint(2, "mbSearch %s\n", elem);
735e96a66cSDavid du Colombier
745e96a66cSDavid du Colombier /* binary search within block */
755e96a66cSDavid du Colombier b = 0;
765e96a66cSDavid du Colombier t = mb->nindex;
775e96a66cSDavid du Colombier while(b < t){
785e96a66cSDavid du Colombier i = (b+t)>>1;
795e96a66cSDavid du Colombier meUnpack(me, mb, i);
805e96a66cSDavid du Colombier
815e96a66cSDavid du Colombier if(mb->botch)
825e96a66cSDavid du Colombier x = meCmpOld(me, elem);
835e96a66cSDavid du Colombier else
845e96a66cSDavid du Colombier x = meCmp(me, elem);
855e96a66cSDavid du Colombier
865e96a66cSDavid du Colombier if(x == 0){
875e96a66cSDavid du Colombier *ri = i;
885e96a66cSDavid du Colombier return 1;
895e96a66cSDavid du Colombier }
905e96a66cSDavid du Colombier
915e96a66cSDavid du Colombier if(x < 0)
925e96a66cSDavid du Colombier b = i+1;
935e96a66cSDavid du Colombier else /* x > 0 */
945e96a66cSDavid du Colombier t = i;
955e96a66cSDavid du Colombier }
965e96a66cSDavid du Colombier
975e96a66cSDavid du Colombier assert(b == t);
985e96a66cSDavid du Colombier
995e96a66cSDavid du Colombier *ri = b; /* b is the index to insert this entry */
1005e96a66cSDavid du Colombier memset(me, 0, sizeof(*me));
1015e96a66cSDavid du Colombier
1025e96a66cSDavid du Colombier vtSetError(ENoFile);
1035e96a66cSDavid du Colombier return 0;
1045e96a66cSDavid du Colombier }
1055e96a66cSDavid du Colombier
1065e96a66cSDavid du Colombier void
mbInit(MetaBlock * mb,uchar * p,int n,int ne)1075e96a66cSDavid du Colombier mbInit(MetaBlock *mb, uchar *p, int n, int ne)
1085e96a66cSDavid du Colombier {
1095e96a66cSDavid du Colombier memset(p, 0, n);
1105e96a66cSDavid du Colombier mb->maxsize = n;
1115e96a66cSDavid du Colombier mb->maxindex = ne;
1125e96a66cSDavid du Colombier mb->nindex = 0;
1135e96a66cSDavid du Colombier mb->free = 0;
1145e96a66cSDavid du Colombier mb->size = MetaHeaderSize + ne*MetaIndexSize;
1155e96a66cSDavid du Colombier mb->buf = p;
1165e96a66cSDavid du Colombier mb->botch = 0;
1175e96a66cSDavid du Colombier }
1185e96a66cSDavid du Colombier
1195e96a66cSDavid du Colombier int
mbUnpack(MetaBlock * mb,uchar * p,int n)1205e96a66cSDavid du Colombier mbUnpack(MetaBlock *mb, uchar *p, int n)
1215e96a66cSDavid du Colombier {
1225e96a66cSDavid du Colombier u32int magic;
1235e96a66cSDavid du Colombier int i;
1245e96a66cSDavid du Colombier int eo, en, omin;
1255e96a66cSDavid du Colombier uchar *q;
1265e96a66cSDavid du Colombier
1275e96a66cSDavid du Colombier mb->maxsize = n;
1285e96a66cSDavid du Colombier mb->buf = p;
1295e96a66cSDavid du Colombier
1305e96a66cSDavid du Colombier if(n == 0){
1315e96a66cSDavid du Colombier memset(mb, 0, sizeof(MetaBlock));
1325e96a66cSDavid du Colombier return 1;
1335e96a66cSDavid du Colombier }
1345e96a66cSDavid du Colombier
1355e96a66cSDavid du Colombier magic = U32GET(p);
1365e96a66cSDavid du Colombier if(magic != MetaMagic && magic != MetaMagic-1)
1375e96a66cSDavid du Colombier goto Err;
1385e96a66cSDavid du Colombier mb->size = U16GET(p+4);
1395e96a66cSDavid du Colombier mb->free = U16GET(p+6);
1405e96a66cSDavid du Colombier mb->maxindex = U16GET(p+8);
1415e96a66cSDavid du Colombier mb->nindex = U16GET(p+10);
1425e96a66cSDavid du Colombier mb->botch = magic != MetaMagic;
1435e96a66cSDavid du Colombier if(mb->size > n)
1445e96a66cSDavid du Colombier goto Err;
1455e96a66cSDavid du Colombier
1465e96a66cSDavid du Colombier omin = MetaHeaderSize + mb->maxindex*MetaIndexSize;
1475e96a66cSDavid du Colombier if(n < omin)
1485e96a66cSDavid du Colombier goto Err;
1495e96a66cSDavid du Colombier
1505e96a66cSDavid du Colombier
1515e96a66cSDavid du Colombier p += MetaHeaderSize;
1525e96a66cSDavid du Colombier
1535e96a66cSDavid du Colombier /* check the index table - ensures that meUnpack and meCmp never fail */
1545e96a66cSDavid du Colombier for(i=0; i<mb->nindex; i++){
1555e96a66cSDavid du Colombier eo = U16GET(p);
1565e96a66cSDavid du Colombier en = U16GET(p+2);
1575e96a66cSDavid du Colombier if(eo < omin || eo+en > mb->size || en < 8)
1585e96a66cSDavid du Colombier goto Err;
1595e96a66cSDavid du Colombier q = mb->buf + eo;
1605e96a66cSDavid du Colombier if(U32GET(q) != DirMagic)
1615e96a66cSDavid du Colombier goto Err;
1625e96a66cSDavid du Colombier p += 4;
1635e96a66cSDavid du Colombier }
1645e96a66cSDavid du Colombier
1655e96a66cSDavid du Colombier return 1;
1665e96a66cSDavid du Colombier Err:
1675e96a66cSDavid du Colombier vtSetError(EBadMeta);
1685e96a66cSDavid du Colombier return 0;
1695e96a66cSDavid du Colombier }
1705e96a66cSDavid du Colombier
1715e96a66cSDavid du Colombier
1725e96a66cSDavid du Colombier void
mbPack(MetaBlock * mb)1735e96a66cSDavid du Colombier mbPack(MetaBlock *mb)
1745e96a66cSDavid du Colombier {
1755e96a66cSDavid du Colombier uchar *p;
1765e96a66cSDavid du Colombier
1775e96a66cSDavid du Colombier p = mb->buf;
1785e96a66cSDavid du Colombier
1795e96a66cSDavid du Colombier assert(!mb->botch);
1805e96a66cSDavid du Colombier
1815e96a66cSDavid du Colombier U32PUT(p, MetaMagic);
1825e96a66cSDavid du Colombier U16PUT(p+4, mb->size);
1835e96a66cSDavid du Colombier U16PUT(p+6, mb->free);
1845e96a66cSDavid du Colombier U16PUT(p+8, mb->maxindex);
1855e96a66cSDavid du Colombier U16PUT(p+10, mb->nindex);
1865e96a66cSDavid du Colombier }
1875e96a66cSDavid du Colombier
1885e96a66cSDavid du Colombier
1895e96a66cSDavid du Colombier void
mbDelete(MetaBlock * mb,int i)1905e96a66cSDavid du Colombier mbDelete(MetaBlock *mb, int i)
1915e96a66cSDavid du Colombier {
1925e96a66cSDavid du Colombier uchar *p;
1935e96a66cSDavid du Colombier int n;
1945e96a66cSDavid du Colombier MetaEntry me;
1955e96a66cSDavid du Colombier
1965e96a66cSDavid du Colombier assert(i < mb->nindex);
1975e96a66cSDavid du Colombier meUnpack(&me, mb, i);
1985e96a66cSDavid du Colombier memset(me.p, 0, me.size);
1995e96a66cSDavid du Colombier
2005e96a66cSDavid du Colombier if(me.p - mb->buf + me.size == mb->size)
2015e96a66cSDavid du Colombier mb->size -= me.size;
2025e96a66cSDavid du Colombier else
2035e96a66cSDavid du Colombier mb->free += me.size;
2045e96a66cSDavid du Colombier
2055e96a66cSDavid du Colombier p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
2065e96a66cSDavid du Colombier n = (mb->nindex-i-1)*MetaIndexSize;
2075e96a66cSDavid du Colombier memmove(p, p+MetaIndexSize, n);
2085e96a66cSDavid du Colombier memset(p+n, 0, MetaIndexSize);
2095e96a66cSDavid du Colombier mb->nindex--;
2105e96a66cSDavid du Colombier }
2115e96a66cSDavid du Colombier
2125e96a66cSDavid du Colombier void
mbInsert(MetaBlock * mb,int i,MetaEntry * me)2135e96a66cSDavid du Colombier mbInsert(MetaBlock *mb, int i, MetaEntry *me)
2145e96a66cSDavid du Colombier {
2155e96a66cSDavid du Colombier uchar *p;
2165e96a66cSDavid du Colombier int o, n;
2175e96a66cSDavid du Colombier
2185e96a66cSDavid du Colombier assert(mb->nindex < mb->maxindex);
2195e96a66cSDavid du Colombier
2205e96a66cSDavid du Colombier o = me->p - mb->buf;
2215e96a66cSDavid du Colombier n = me->size;
2225e96a66cSDavid du Colombier if(o+n > mb->size){
2235e96a66cSDavid du Colombier mb->free -= mb->size - o;
2245e96a66cSDavid du Colombier mb->size = o + n;
2255e96a66cSDavid du Colombier }else
2265e96a66cSDavid du Colombier mb->free -= n;
2275e96a66cSDavid du Colombier
2285e96a66cSDavid du Colombier p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
2295e96a66cSDavid du Colombier n = (mb->nindex-i)*MetaIndexSize;
2305e96a66cSDavid du Colombier memmove(p+MetaIndexSize, p, n);
2315e96a66cSDavid du Colombier U16PUT(p, me->p - mb->buf);
2325e96a66cSDavid du Colombier U16PUT(p+2, me->size);
2335e96a66cSDavid du Colombier mb->nindex++;
2345e96a66cSDavid du Colombier }
2355e96a66cSDavid du Colombier
2365e96a66cSDavid du Colombier int
mbResize(MetaBlock * mb,MetaEntry * me,int n)2375e96a66cSDavid du Colombier mbResize(MetaBlock *mb, MetaEntry *me, int n)
2385e96a66cSDavid du Colombier {
2395e96a66cSDavid du Colombier uchar *p, *ep;
2405e96a66cSDavid du Colombier
2415e96a66cSDavid du Colombier /* easy case */
2425e96a66cSDavid du Colombier if(n <= me->size){
2435e96a66cSDavid du Colombier me->size = n;
2445e96a66cSDavid du Colombier return 1;
2455e96a66cSDavid du Colombier }
2465e96a66cSDavid du Colombier
2475e96a66cSDavid du Colombier /* try and expand entry */
2485e96a66cSDavid du Colombier
2495e96a66cSDavid du Colombier p = me->p + me->size;
2505e96a66cSDavid du Colombier ep = mb->buf + mb->maxsize;
2515e96a66cSDavid du Colombier while(p < ep && *p == 0)
2525e96a66cSDavid du Colombier p++;
2535e96a66cSDavid du Colombier if(n <= p - me->p){
2545e96a66cSDavid du Colombier me->size = n;
2555e96a66cSDavid du Colombier return 1;
2565e96a66cSDavid du Colombier }
2575e96a66cSDavid du Colombier
2585e96a66cSDavid du Colombier p = mbAlloc(mb, n);
2595e96a66cSDavid du Colombier if(p != nil){
2605e96a66cSDavid du Colombier me->p = p;
2615e96a66cSDavid du Colombier me->size = n;
2625e96a66cSDavid du Colombier return 1;
2635e96a66cSDavid du Colombier }
2645e96a66cSDavid du Colombier
2655e96a66cSDavid du Colombier return 0;
2665e96a66cSDavid du Colombier }
2675e96a66cSDavid du Colombier
2685e96a66cSDavid du Colombier void
meUnpack(MetaEntry * me,MetaBlock * mb,int i)2695e96a66cSDavid du Colombier meUnpack(MetaEntry *me, MetaBlock *mb, int i)
2705e96a66cSDavid du Colombier {
2715e96a66cSDavid du Colombier uchar *p;
2725e96a66cSDavid du Colombier int eo, en;
2735e96a66cSDavid du Colombier
2745e96a66cSDavid du Colombier assert(i >= 0 && i < mb->nindex);
2755e96a66cSDavid du Colombier
2765e96a66cSDavid du Colombier p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
2775e96a66cSDavid du Colombier eo = U16GET(p);
2785e96a66cSDavid du Colombier en = U16GET(p+2);
2795e96a66cSDavid du Colombier
2805e96a66cSDavid du Colombier me->p = mb->buf + eo;
2815e96a66cSDavid du Colombier me->size = en;
2825e96a66cSDavid du Colombier
2835e96a66cSDavid du Colombier /* checked by mbUnpack */
2845e96a66cSDavid du Colombier assert(me->size >= 8);
2855e96a66cSDavid du Colombier }
2865e96a66cSDavid du Colombier
2875e96a66cSDavid du Colombier /* assumes a small amount of checking has been done in mbEntry */
2885e96a66cSDavid du Colombier static int
meCmp(MetaEntry * me,char * s)2895e96a66cSDavid du Colombier meCmp(MetaEntry *me, char *s)
2905e96a66cSDavid du Colombier {
2915e96a66cSDavid du Colombier int n;
2925e96a66cSDavid du Colombier uchar *p;
2935e96a66cSDavid du Colombier
2945e96a66cSDavid du Colombier p = me->p;
2955e96a66cSDavid du Colombier
2965e96a66cSDavid du Colombier /* skip magic & version */
2975e96a66cSDavid du Colombier p += 6;
2985e96a66cSDavid du Colombier n = U16GET(p);
2995e96a66cSDavid du Colombier p += 2;
3005e96a66cSDavid du Colombier
3015e96a66cSDavid du Colombier if(n > me->size - 8)
3025e96a66cSDavid du Colombier n = me->size - 8;
3035e96a66cSDavid du Colombier
3045e96a66cSDavid du Colombier while(n > 0){
3055e96a66cSDavid du Colombier if(*s == 0)
3065e96a66cSDavid du Colombier return 1;
3075e96a66cSDavid du Colombier if(*p < (uchar)*s)
3085e96a66cSDavid du Colombier return -1;
3095e96a66cSDavid du Colombier if(*p > (uchar)*s)
3105e96a66cSDavid du Colombier return 1;
3115e96a66cSDavid du Colombier p++;
3125e96a66cSDavid du Colombier s++;
3135e96a66cSDavid du Colombier n--;
3145e96a66cSDavid du Colombier }
3155e96a66cSDavid du Colombier return -(*s != 0);
3165e96a66cSDavid du Colombier }
3175e96a66cSDavid du Colombier
3185e96a66cSDavid du Colombier /*
3195e96a66cSDavid du Colombier * This is the old and broken meCmp.
3205e96a66cSDavid du Colombier * This cmp routine reverse the sense of the comparison
3215e96a66cSDavid du Colombier * when one string is a prefix of the other.
3225e96a66cSDavid du Colombier * In other words, it put "ab" after "abc" rather
3235e96a66cSDavid du Colombier * than before. This behaviour is ok; binary search
3245e96a66cSDavid du Colombier * and sort still work. However, it is goes against
3255e96a66cSDavid du Colombier * the usual convention.
3265e96a66cSDavid du Colombier */
3275e96a66cSDavid du Colombier static int
meCmpOld(MetaEntry * me,char * s)3285e96a66cSDavid du Colombier meCmpOld(MetaEntry *me, char *s)
3295e96a66cSDavid du Colombier {
3305e96a66cSDavid du Colombier int n;
3315e96a66cSDavid du Colombier uchar *p;
3325e96a66cSDavid du Colombier
3335e96a66cSDavid du Colombier p = me->p;
3345e96a66cSDavid du Colombier
3355e96a66cSDavid du Colombier /* skip magic & version */
3365e96a66cSDavid du Colombier p += 6;
3375e96a66cSDavid du Colombier n = U16GET(p);
3385e96a66cSDavid du Colombier p += 2;
3395e96a66cSDavid du Colombier
3405e96a66cSDavid du Colombier if(n > me->size - 8)
3415e96a66cSDavid du Colombier n = me->size - 8;
3425e96a66cSDavid du Colombier
3435e96a66cSDavid du Colombier while(n > 0){
3445e96a66cSDavid du Colombier if(*s == 0)
3455e96a66cSDavid du Colombier return -1;
3465e96a66cSDavid du Colombier if(*p < (uchar)*s)
3475e96a66cSDavid du Colombier return -1;
3485e96a66cSDavid du Colombier if(*p > (uchar)*s)
3495e96a66cSDavid du Colombier return 1;
3505e96a66cSDavid du Colombier p++;
3515e96a66cSDavid du Colombier s++;
3525e96a66cSDavid du Colombier n--;
3535e96a66cSDavid du Colombier }
3545e96a66cSDavid du Colombier return *s != 0;
3555e96a66cSDavid du Colombier }
3565e96a66cSDavid du Colombier
3575e96a66cSDavid du Colombier static int
offsetCmp(void * s0,void * s1)3585e96a66cSDavid du Colombier offsetCmp(void *s0, void *s1)
3595e96a66cSDavid du Colombier {
3605e96a66cSDavid du Colombier MetaChunk *mc0, *mc1;
3615e96a66cSDavid du Colombier
3625e96a66cSDavid du Colombier mc0 = s0;
3635e96a66cSDavid du Colombier mc1 = s1;
3645e96a66cSDavid du Colombier if(mc0->offset < mc1->offset)
3655e96a66cSDavid du Colombier return -1;
3665e96a66cSDavid du Colombier if(mc0->offset > mc1->offset)
3675e96a66cSDavid du Colombier return 1;
3685e96a66cSDavid du Colombier return 0;
3695e96a66cSDavid du Colombier }
3705e96a66cSDavid du Colombier
3715e96a66cSDavid du Colombier static MetaChunk *
metaChunks(MetaBlock * mb)3725e96a66cSDavid du Colombier metaChunks(MetaBlock *mb)
3735e96a66cSDavid du Colombier {
3745e96a66cSDavid du Colombier MetaChunk *mc;
3755e96a66cSDavid du Colombier int oo, o, n, i;
3765e96a66cSDavid du Colombier uchar *p;
3775e96a66cSDavid du Colombier
3785e96a66cSDavid du Colombier mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
3795e96a66cSDavid du Colombier p = mb->buf + MetaHeaderSize;
3805e96a66cSDavid du Colombier for(i = 0; i<mb->nindex; i++){
3815e96a66cSDavid du Colombier mc[i].offset = U16GET(p);
3825e96a66cSDavid du Colombier mc[i].size = U16GET(p+2);
3835e96a66cSDavid du Colombier mc[i].index = i;
3845e96a66cSDavid du Colombier p += MetaIndexSize;
3855e96a66cSDavid du Colombier }
3865e96a66cSDavid du Colombier
3875e96a66cSDavid du Colombier qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
3885e96a66cSDavid du Colombier
3895e96a66cSDavid du Colombier /* check block looks ok */
3905e96a66cSDavid du Colombier oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
3915e96a66cSDavid du Colombier o = oo;
3925e96a66cSDavid du Colombier n = 0;
3935e96a66cSDavid du Colombier for(i=0; i<mb->nindex; i++){
3945e96a66cSDavid du Colombier o = mc[i].offset;
3955e96a66cSDavid du Colombier n = mc[i].size;
3965e96a66cSDavid du Colombier if(o < oo)
3975e96a66cSDavid du Colombier goto Err;
3985e96a66cSDavid du Colombier oo += n;
3995e96a66cSDavid du Colombier }
4005e96a66cSDavid du Colombier if(o+n > mb->size)
4015e96a66cSDavid du Colombier goto Err;
4025e96a66cSDavid du Colombier if(mb->size - oo != mb->free)
4035e96a66cSDavid du Colombier goto Err;
4045e96a66cSDavid du Colombier
4055e96a66cSDavid du Colombier return mc;
4065e96a66cSDavid du Colombier Err:
4075e96a66cSDavid du Colombier fprint(2, "metaChunks failed!\n");
4085e96a66cSDavid du Colombier oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
4095e96a66cSDavid du Colombier for(i=0; i<mb->nindex; i++){
4105e96a66cSDavid du Colombier fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size);
4115e96a66cSDavid du Colombier oo += mc[i].size;
4125e96a66cSDavid du Colombier }
4135e96a66cSDavid du Colombier fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo);
4145e96a66cSDavid du Colombier vtSetError(EBadMeta);
4155e96a66cSDavid du Colombier vtMemFree(mc);
4165e96a66cSDavid du Colombier return nil;
4175e96a66cSDavid du Colombier }
4185e96a66cSDavid du Colombier
4195e96a66cSDavid du Colombier static void
mbCompact(MetaBlock * mb,MetaChunk * mc)4205e96a66cSDavid du Colombier mbCompact(MetaBlock *mb, MetaChunk *mc)
4215e96a66cSDavid du Colombier {
4225e96a66cSDavid du Colombier int oo, o, n, i;
4235e96a66cSDavid du Colombier
4245e96a66cSDavid du Colombier oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
4255e96a66cSDavid du Colombier
4265e96a66cSDavid du Colombier for(i=0; i<mb->nindex; i++){
4275e96a66cSDavid du Colombier o = mc[i].offset;
4285e96a66cSDavid du Colombier n = mc[i].size;
4295e96a66cSDavid du Colombier if(o != oo){
4305e96a66cSDavid du Colombier memmove(mb->buf + oo, mb->buf + o, n);
4315e96a66cSDavid du Colombier U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
4325e96a66cSDavid du Colombier }
4335e96a66cSDavid du Colombier oo += n;
4345e96a66cSDavid du Colombier }
4355e96a66cSDavid du Colombier
4365e96a66cSDavid du Colombier mb->size = oo;
4375e96a66cSDavid du Colombier mb->free = 0;
4385e96a66cSDavid du Colombier }
4395e96a66cSDavid du Colombier
4405e96a66cSDavid du Colombier uchar *
mbAlloc(MetaBlock * mb,int n)4415e96a66cSDavid du Colombier mbAlloc(MetaBlock *mb, int n)
4425e96a66cSDavid du Colombier {
4435e96a66cSDavid du Colombier int i, o;
4445e96a66cSDavid du Colombier MetaChunk *mc;
4455e96a66cSDavid du Colombier
4465e96a66cSDavid du Colombier /* off the end */
4475e96a66cSDavid du Colombier if(mb->maxsize - mb->size >= n)
4485e96a66cSDavid du Colombier return mb->buf + mb->size;
4495e96a66cSDavid du Colombier
4505e96a66cSDavid du Colombier /* check if possible */
4515e96a66cSDavid du Colombier if(mb->maxsize - mb->size + mb->free < n)
4525e96a66cSDavid du Colombier return nil;
4535e96a66cSDavid du Colombier
4545e96a66cSDavid du Colombier mc = metaChunks(mb);
4555e96a66cSDavid du Colombier if(mc == nil){
4565e96a66cSDavid du Colombier fprint(2, "mbAlloc: metaChunks failed: %r\n");
4575e96a66cSDavid du Colombier return nil;
4585e96a66cSDavid du Colombier }
4595e96a66cSDavid du Colombier
4605e96a66cSDavid du Colombier /* look for hole */
4615e96a66cSDavid du Colombier o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
4625e96a66cSDavid du Colombier for(i=0; i<mb->nindex; i++){
4635e96a66cSDavid du Colombier if(mc[i].offset - o >= n){
4645e96a66cSDavid du Colombier vtMemFree(mc);
4655e96a66cSDavid du Colombier return mb->buf + o;
4665e96a66cSDavid du Colombier }
4675e96a66cSDavid du Colombier o = mc[i].offset + mc[i].size;
4685e96a66cSDavid du Colombier }
4695e96a66cSDavid du Colombier
4705e96a66cSDavid du Colombier if(mb->maxsize - o >= n){
4715e96a66cSDavid du Colombier vtMemFree(mc);
4725e96a66cSDavid du Colombier return mb->buf + o;
4735e96a66cSDavid du Colombier }
4745e96a66cSDavid du Colombier
4755e96a66cSDavid du Colombier /* compact and return off the end */
4765e96a66cSDavid du Colombier mbCompact(mb, mc);
4775e96a66cSDavid du Colombier vtMemFree(mc);
4785e96a66cSDavid du Colombier
4795e96a66cSDavid du Colombier if(mb->maxsize - mb->size < n){
4805e96a66cSDavid du Colombier vtSetError(EBadMeta);
4815e96a66cSDavid du Colombier return nil;
4825e96a66cSDavid du Colombier }
4835e96a66cSDavid du Colombier return mb->buf + mb->size;
4845e96a66cSDavid du Colombier }
4855e96a66cSDavid du Colombier
4865e96a66cSDavid du Colombier int
deSize(DirEntry * dir)4875e96a66cSDavid du Colombier deSize(DirEntry *dir)
4885e96a66cSDavid du Colombier {
4895e96a66cSDavid du Colombier int n;
4905e96a66cSDavid du Colombier
4915e96a66cSDavid du Colombier /* constant part */
4925e96a66cSDavid du Colombier
4935e96a66cSDavid du Colombier n = 4 + /* magic */
4945e96a66cSDavid du Colombier 2 + /* version */
4955e96a66cSDavid du Colombier 4 + /* entry */
4965e96a66cSDavid du Colombier 4 + /* guid */
4975e96a66cSDavid du Colombier 4 + /* mentry */
4985e96a66cSDavid du Colombier 4 + /* mgen */
4995e96a66cSDavid du Colombier 8 + /* qid */
5005e96a66cSDavid du Colombier 4 + /* mtime */
5015e96a66cSDavid du Colombier 4 + /* mcount */
5025e96a66cSDavid du Colombier 4 + /* ctime */
5035e96a66cSDavid du Colombier 4 + /* atime */
5045e96a66cSDavid du Colombier 4 + /* mode */
5055e96a66cSDavid du Colombier 0;
5065e96a66cSDavid du Colombier
5075e96a66cSDavid du Colombier /* strings */
5085e96a66cSDavid du Colombier n += 2 + strlen(dir->elem);
5095e96a66cSDavid du Colombier n += 2 + strlen(dir->uid);
5105e96a66cSDavid du Colombier n += 2 + strlen(dir->gid);
5115e96a66cSDavid du Colombier n += 2 + strlen(dir->mid);
5125e96a66cSDavid du Colombier
5135e96a66cSDavid du Colombier /* optional sections */
5145e96a66cSDavid du Colombier if(dir->qidSpace){
5155e96a66cSDavid du Colombier n += 3 + /* option header */
5165e96a66cSDavid du Colombier 8 + /* qidOffset */
5175e96a66cSDavid du Colombier 8; /* qid Max */
5185e96a66cSDavid du Colombier }
5195e96a66cSDavid du Colombier
5205e96a66cSDavid du Colombier return n;
5215e96a66cSDavid du Colombier }
5225e96a66cSDavid du Colombier
5235e96a66cSDavid du Colombier void
dePack(DirEntry * dir,MetaEntry * me)5245e96a66cSDavid du Colombier dePack(DirEntry *dir, MetaEntry *me)
5255e96a66cSDavid du Colombier {
5265e96a66cSDavid du Colombier uchar *p;
5275e96a66cSDavid du Colombier ulong t32;
5285e96a66cSDavid du Colombier
5295e96a66cSDavid du Colombier p = me->p;
5305e96a66cSDavid du Colombier
5315e96a66cSDavid du Colombier U32PUT(p, DirMagic);
5325e96a66cSDavid du Colombier U16PUT(p+4, 9); /* version */
5335e96a66cSDavid du Colombier p += 6;
5345e96a66cSDavid du Colombier
5355e96a66cSDavid du Colombier p += stringPack(dir->elem, p);
5365e96a66cSDavid du Colombier
5375e96a66cSDavid du Colombier U32PUT(p, dir->entry);
5385e96a66cSDavid du Colombier U32PUT(p+4, dir->gen);
5395e96a66cSDavid du Colombier U32PUT(p+8, dir->mentry);
5405e96a66cSDavid du Colombier U32PUT(p+12, dir->mgen);
5415e96a66cSDavid du Colombier U64PUT(p+16, dir->qid, t32);
5425e96a66cSDavid du Colombier p += 24;
5435e96a66cSDavid du Colombier
5445e96a66cSDavid du Colombier p += stringPack(dir->uid, p);
5455e96a66cSDavid du Colombier p += stringPack(dir->gid, p);
5465e96a66cSDavid du Colombier p += stringPack(dir->mid, p);
5475e96a66cSDavid du Colombier
5485e96a66cSDavid du Colombier U32PUT(p, dir->mtime);
5495e96a66cSDavid du Colombier U32PUT(p+4, dir->mcount);
5505e96a66cSDavid du Colombier U32PUT(p+8, dir->ctime);
5515e96a66cSDavid du Colombier U32PUT(p+12, dir->atime);
5525e96a66cSDavid du Colombier U32PUT(p+16, dir->mode);
5535e96a66cSDavid du Colombier p += 5*4;
5545e96a66cSDavid du Colombier
5555e96a66cSDavid du Colombier if(dir->qidSpace){
5565e96a66cSDavid du Colombier U8PUT(p, DeQidSpace);
5575e96a66cSDavid du Colombier U16PUT(p+1, 2*8);
5585e96a66cSDavid du Colombier p += 3;
5595e96a66cSDavid du Colombier U64PUT(p, dir->qidOffset, t32);
5605e96a66cSDavid du Colombier U64PUT(p+8, dir->qidMax, t32);
5615e96a66cSDavid du Colombier p += 16;
5625e96a66cSDavid du Colombier }
5635e96a66cSDavid du Colombier
5645e96a66cSDavid du Colombier assert(p == me->p + me->size);
5655e96a66cSDavid du Colombier }
5665e96a66cSDavid du Colombier
5675e96a66cSDavid du Colombier
5685e96a66cSDavid du Colombier int
deUnpack(DirEntry * dir,MetaEntry * me)5695e96a66cSDavid du Colombier deUnpack(DirEntry *dir, MetaEntry *me)
5705e96a66cSDavid du Colombier {
5715e96a66cSDavid du Colombier int t, nn, n, version;
5725e96a66cSDavid du Colombier uchar *p;
5735e96a66cSDavid du Colombier
5745e96a66cSDavid du Colombier p = me->p;
5755e96a66cSDavid du Colombier n = me->size;
5765e96a66cSDavid du Colombier
5775e96a66cSDavid du Colombier memset(dir, 0, sizeof(DirEntry));
5785e96a66cSDavid du Colombier
579*6042bf6dSDavid du Colombier if(0)print("deUnpack\n");
5805e96a66cSDavid du Colombier /* magic */
5815e96a66cSDavid du Colombier if(n < 4 || U32GET(p) != DirMagic)
5825e96a66cSDavid du Colombier goto Err;
5835e96a66cSDavid du Colombier p += 4;
5845e96a66cSDavid du Colombier n -= 4;
5855e96a66cSDavid du Colombier
586*6042bf6dSDavid du Colombier if(0)print("deUnpack: got magic\n");
5875e96a66cSDavid du Colombier /* version */
5885e96a66cSDavid du Colombier if(n < 2)
5895e96a66cSDavid du Colombier goto Err;
5905e96a66cSDavid du Colombier version = U16GET(p);
5915e96a66cSDavid du Colombier if(version < 7 || version > 9)
5925e96a66cSDavid du Colombier goto Err;
5935e96a66cSDavid du Colombier p += 2;
5945e96a66cSDavid du Colombier n -= 2;
5955e96a66cSDavid du Colombier
596*6042bf6dSDavid du Colombier if(0)print("deUnpack: got version\n");
5975e96a66cSDavid du Colombier
5985e96a66cSDavid du Colombier /* elem */
5995e96a66cSDavid du Colombier if(!stringUnpack(&dir->elem, &p, &n))
6005e96a66cSDavid du Colombier goto Err;
6015e96a66cSDavid du Colombier
602*6042bf6dSDavid du Colombier if(0)print("deUnpack: got elem\n");
6035e96a66cSDavid du Colombier
6045e96a66cSDavid du Colombier /* entry */
6055e96a66cSDavid du Colombier if(n < 4)
6065e96a66cSDavid du Colombier goto Err;
6075e96a66cSDavid du Colombier dir->entry = U32GET(p);
6085e96a66cSDavid du Colombier p += 4;
6095e96a66cSDavid du Colombier n -= 4;
6105e96a66cSDavid du Colombier
611*6042bf6dSDavid du Colombier if(0)print("deUnpack: got entry\n");
6125e96a66cSDavid du Colombier
6135e96a66cSDavid du Colombier if(version < 9){
6145e96a66cSDavid du Colombier dir->gen = 0;
6155e96a66cSDavid du Colombier dir->mentry = dir->entry+1;
6165e96a66cSDavid du Colombier dir->mgen = 0;
6175e96a66cSDavid du Colombier }else{
6185e96a66cSDavid du Colombier if(n < 3*4)
6195e96a66cSDavid du Colombier goto Err;
6205e96a66cSDavid du Colombier dir->gen = U32GET(p);
6215e96a66cSDavid du Colombier dir->mentry = U32GET(p+4);
6225e96a66cSDavid du Colombier dir->mgen = U32GET(p+8);
6235e96a66cSDavid du Colombier p += 3*4;
6245e96a66cSDavid du Colombier n -= 3*4;
6255e96a66cSDavid du Colombier }
6265e96a66cSDavid du Colombier
627*6042bf6dSDavid du Colombier if(0)print("deUnpack: got gen etc\n");
6285e96a66cSDavid du Colombier
6295e96a66cSDavid du Colombier /* size is gotten from VtEntry */
6305e96a66cSDavid du Colombier dir->size = 0;
6315e96a66cSDavid du Colombier
6325e96a66cSDavid du Colombier /* qid */
6335e96a66cSDavid du Colombier if(n < 8)
6345e96a66cSDavid du Colombier goto Err;
6355e96a66cSDavid du Colombier dir->qid = U64GET(p);
6365e96a66cSDavid du Colombier p += 8;
6375e96a66cSDavid du Colombier n -= 8;
6385e96a66cSDavid du Colombier
639*6042bf6dSDavid du Colombier if(0)print("deUnpack: got qid\n");
6405e96a66cSDavid du Colombier /* skip replacement */
6415e96a66cSDavid du Colombier if(version == 7){
6425e96a66cSDavid du Colombier if(n < VtScoreSize)
6435e96a66cSDavid du Colombier goto Err;
6445e96a66cSDavid du Colombier p += VtScoreSize;
6455e96a66cSDavid du Colombier n -= VtScoreSize;
6465e96a66cSDavid du Colombier }
6475e96a66cSDavid du Colombier
6485e96a66cSDavid du Colombier /* uid */
6495e96a66cSDavid du Colombier if(!stringUnpack(&dir->uid, &p, &n))
6505e96a66cSDavid du Colombier goto Err;
6515e96a66cSDavid du Colombier
6525e96a66cSDavid du Colombier /* gid */
6535e96a66cSDavid du Colombier if(!stringUnpack(&dir->gid, &p, &n))
6545e96a66cSDavid du Colombier goto Err;
6555e96a66cSDavid du Colombier
6565e96a66cSDavid du Colombier /* mid */
6575e96a66cSDavid du Colombier if(!stringUnpack(&dir->mid, &p, &n))
6585e96a66cSDavid du Colombier goto Err;
6595e96a66cSDavid du Colombier
660*6042bf6dSDavid du Colombier if(0)print("deUnpack: got ids\n");
6615e96a66cSDavid du Colombier if(n < 5*4)
6625e96a66cSDavid du Colombier goto Err;
6635e96a66cSDavid du Colombier dir->mtime = U32GET(p);
6645e96a66cSDavid du Colombier dir->mcount = U32GET(p+4);
6655e96a66cSDavid du Colombier dir->ctime = U32GET(p+8);
6665e96a66cSDavid du Colombier dir->atime = U32GET(p+12);
6675e96a66cSDavid du Colombier dir->mode = U32GET(p+16);
6685e96a66cSDavid du Colombier p += 5*4;
6695e96a66cSDavid du Colombier n -= 5*4;
6705e96a66cSDavid du Colombier
671*6042bf6dSDavid du Colombier if(0)print("deUnpack: got times\n");
6725e96a66cSDavid du Colombier /* optional meta data */
6735e96a66cSDavid du Colombier while(n > 0){
6745e96a66cSDavid du Colombier if(n < 3)
6755e96a66cSDavid du Colombier goto Err;
6765e96a66cSDavid du Colombier t = p[0];
6775e96a66cSDavid du Colombier nn = U16GET(p+1);
6785e96a66cSDavid du Colombier p += 3;
6795e96a66cSDavid du Colombier n -= 3;
6805e96a66cSDavid du Colombier if(n < nn)
6815e96a66cSDavid du Colombier goto Err;
6825e96a66cSDavid du Colombier switch(t){
6835e96a66cSDavid du Colombier case DePlan9:
6845e96a66cSDavid du Colombier /* not valid in version >= 9 */
6855e96a66cSDavid du Colombier if(version >= 9)
6865e96a66cSDavid du Colombier break;
6875e96a66cSDavid du Colombier if(dir->plan9 || nn != 12)
6885e96a66cSDavid du Colombier goto Err;
6895e96a66cSDavid du Colombier dir->plan9 = 1;
6905e96a66cSDavid du Colombier dir->p9path = U64GET(p);
6915e96a66cSDavid du Colombier dir->p9version = U32GET(p+8);
6925e96a66cSDavid du Colombier if(dir->mcount == 0)
6935e96a66cSDavid du Colombier dir->mcount = dir->p9version;
6945e96a66cSDavid du Colombier break;
6955e96a66cSDavid du Colombier case DeGen:
6965e96a66cSDavid du Colombier /* not valid in version >= 9 */
6975e96a66cSDavid du Colombier if(version >= 9)
6985e96a66cSDavid du Colombier break;
6995e96a66cSDavid du Colombier break;
7005e96a66cSDavid du Colombier case DeQidSpace:
7015e96a66cSDavid du Colombier if(dir->qidSpace || nn != 16)
7025e96a66cSDavid du Colombier goto Err;
7035e96a66cSDavid du Colombier dir->qidSpace = 1;
7045e96a66cSDavid du Colombier dir->qidOffset = U64GET(p);
7055e96a66cSDavid du Colombier dir->qidMax = U64GET(p+8);
7065e96a66cSDavid du Colombier break;
7075e96a66cSDavid du Colombier }
7085e96a66cSDavid du Colombier p += nn;
7095e96a66cSDavid du Colombier n -= nn;
7105e96a66cSDavid du Colombier }
711*6042bf6dSDavid du Colombier if(0)print("deUnpack: got options\n");
7125e96a66cSDavid du Colombier
7135e96a66cSDavid du Colombier if(p != me->p + me->size)
7145e96a66cSDavid du Colombier goto Err;
7155e96a66cSDavid du Colombier
716*6042bf6dSDavid du Colombier if(0)print("deUnpack: correct size\n");
7175e96a66cSDavid du Colombier return 1;
7185e96a66cSDavid du Colombier Err:
719*6042bf6dSDavid du Colombier if(0)print("deUnpack: XXXXXXXXXXXX EBadMeta\n");
7205e96a66cSDavid du Colombier vtSetError(EBadMeta);
7215e96a66cSDavid du Colombier deCleanup(dir);
7225e96a66cSDavid du Colombier return 0;
7235e96a66cSDavid du Colombier }
7245e96a66cSDavid du Colombier
7255e96a66cSDavid du Colombier void
deCleanup(DirEntry * dir)7265e96a66cSDavid du Colombier deCleanup(DirEntry *dir)
7275e96a66cSDavid du Colombier {
7285e96a66cSDavid du Colombier vtMemFree(dir->elem);
7295e96a66cSDavid du Colombier dir->elem = nil;
7305e96a66cSDavid du Colombier vtMemFree(dir->uid);
7315e96a66cSDavid du Colombier dir->uid = nil;
7325e96a66cSDavid du Colombier vtMemFree(dir->gid);
7335e96a66cSDavid du Colombier dir->gid = nil;
7345e96a66cSDavid du Colombier vtMemFree(dir->mid);
7355e96a66cSDavid du Colombier dir->mid = nil;
7365e96a66cSDavid du Colombier }
7375e96a66cSDavid du Colombier
7385e96a66cSDavid du Colombier void
deCopy(DirEntry * dst,DirEntry * src)7395e96a66cSDavid du Colombier deCopy(DirEntry *dst, DirEntry *src)
7405e96a66cSDavid du Colombier {
7415e96a66cSDavid du Colombier *dst = *src;
7425e96a66cSDavid du Colombier dst->elem = vtStrDup(src->elem);
7435e96a66cSDavid du Colombier dst->uid = vtStrDup(src->uid);
7445e96a66cSDavid du Colombier dst->gid = vtStrDup(src->gid);
7455e96a66cSDavid du Colombier dst->mid = vtStrDup(src->mid);
7465e96a66cSDavid du Colombier }
747