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