URI:
       tzipfs.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
       ---
       tzipfs.c (6597B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include <flate.h>
            5 #include <auth.h>
            6 #include <fcall.h>
            7 #include <ctype.h>
            8 #include "tapefs.h"
            9 #include "zip.h"
           10 
           11 #define FORCE_LOWER        1        /* force filenames to lower case */
           12 #define MUNGE_CR        1        /* replace '\r\n' with ' \n' */
           13 #define High64 (1LL<<63)
           14 
           15 /*
           16  * File system for zip archives (read-only)
           17  */
           18 
           19 enum {
           20         IS_MSDOS = 0,        /* creator OS (interpretation of external flags) */
           21         IS_RDONLY = 1,        /* file was readonly (external flags) */
           22         IS_TEXT = 1        /* file was text  (internal flags) */
           23 };
           24 
           25 typedef struct Block Block;
           26 struct Block{
           27         uchar *pos;
           28         uchar *limit;
           29 };
           30 
           31 static Biobuf *bin;
           32 static u32int *crctab;
           33 static ulong crc;
           34 
           35 static int findCDir(Biobuf *);
           36 static int header(Biobuf *, ZipHead *);
           37 static int cheader(Biobuf *, ZipHead *);
           38 /* static void trailer(Biobuf *, ZipHead *); */
           39 static char *getname(Biobuf *, int);
           40 static int blwrite(void *, void *, int);
           41 static ulong get4(Biobuf *);
           42 static int get2(Biobuf *);
           43 static int get1(Biobuf *);
           44 static long msdos2time(int, int);
           45 
           46 void
           47 populate(char *name)
           48 {
           49         char *p;
           50         Fileinf f;
           51         ZipHead zh;
           52         int ok, entries;
           53 
           54         crctab = mkcrctab(ZCrcPoly);
           55         ok = inflateinit();
           56         if(ok != FlateOk)
           57                 sysfatal("inflateinit failed: %s", flateerr(ok));
           58 
           59         bin = Bopen(name, OREAD);
           60         if (bin == nil)
           61                 error("Can't open argument file");
           62 
           63         entries = findCDir(bin);
           64         if(entries < 0)
           65                 sysfatal("empty file");
           66 
           67         while(entries-- > 0){
           68                 memset(&zh, 0, sizeof(zh));
           69                 if(!cheader(bin, &zh))
           70                         break;
           71                 f.addr = zh.off;
           72                 if(zh.iattr & IS_TEXT)
           73                         f.addr |= High64;
           74                 f.mode = (zh.madevers == IS_MSDOS && zh.eattr & IS_RDONLY)? 0444: 0644;
           75                 if (zh.meth == 0 && zh.uncsize == 0){
           76                         p = strchr(zh.file, '\0');
           77                         if(p > zh.file && p[-1] == '/')
           78                                 f.mode |= (DMDIR | 0111);
           79                 }
           80                 f.uid = 0;
           81                 f.gid = 0;
           82                 f.size = zh.uncsize;
           83                 f.mdate = msdos2time(zh.modtime, zh.moddate);
           84                 f.name = zh.file + ((zh.file[0] == '/')? 1: 0);
           85                 poppath(f, 1);
           86                 free(zh.file);
           87         }
           88         return ;
           89 }
           90 
           91 void
           92 dotrunc(Ram *r)
           93 {
           94         USED(r);
           95 }
           96 
           97 void
           98 docreate(Ram *r)
           99 {
          100         USED(r);
          101 }
          102 
          103 char *
          104 doread(Ram *r, vlong off, long cnt)
          105 {
          106         int i, err;
          107         Block bs;
          108         ZipHead zh;
          109         static Qid oqid;
          110         static char buf[Maxbuf];
          111         static uchar *cache = nil;
          112 
          113         if (cnt > Maxbuf)
          114                 sysfatal("file too big (>%d)", Maxbuf);
          115 
          116         if (Bseek(bin, r->addr & 0x7FFFFFFFFFFFFFFFLL, 0) < 0)
          117                 sysfatal("seek failed");
          118 
          119         memset(&zh, 0, sizeof(zh));
          120         if (!header(bin, &zh))
          121                 sysfatal("cannot get local header");
          122 
          123         switch(zh.meth){
          124         case 0:
          125                 if (Bseek(bin, off, 1) < 0)
          126                         sysfatal("seek failed");
          127                 if (Bread(bin, buf, cnt) != cnt)
          128                         sysfatal("read failed");
          129                 break;
          130         case 8:
          131                 if (r->qid.path != oqid.path){
          132                         oqid = r->qid;
          133                         if (cache)
          134                                 free(cache);
          135                         cache = emalloc(r->ndata);
          136 
          137                         bs.pos = cache;
          138                         bs.limit = cache+r->ndata;
          139                         if ((err = inflate(&bs, blwrite, bin, (int(*)(void*))Bgetc)) != FlateOk)
          140                                 sysfatal("inflate failed - %s", flateerr(err));
          141 
          142                         if (blockcrc(crctab, crc, cache, r->ndata) != zh.crc)
          143                                 fprint(2, "%s - crc failed", r->name);
          144 
          145                         if ((r->addr & High64) && MUNGE_CR){
          146                                 for (i = 0; i < r->ndata -1; i++)
          147                                         if (cache[i] == '\r' && cache[i +1] == '\n')
          148                                                 cache[i] = ' ';
          149                         }
          150                 }
          151                 memcpy(buf, cache+off, cnt);
          152                 break;
          153         default:
          154                 sysfatal("%d - unsupported compression method", zh.meth);
          155                 break;
          156         }
          157 
          158         return buf;
          159 }
          160 
          161 void
          162 popdir(Ram *r)
          163 {
          164         USED(r);
          165 }
          166 
          167 void
          168 dowrite(Ram *r, char *buf, long off, long cnt)
          169 {
          170         USED(r); USED(buf); USED(off); USED(cnt);
          171 }
          172 
          173 int
          174 dopermw(Ram *r)
          175 {
          176         USED(r);
          177         return 0;
          178 }
          179 
          180 /*************************************************/
          181 
          182 static int
          183 findCDir(Biobuf *bin)
          184 {
          185         vlong ecoff;
          186         long off;
          187         int entries, zclen;
          188 
          189         ecoff = Bseek(bin, -ZECHeadSize, 2);
          190         if(ecoff < 0)
          191                 sysfatal("can't seek to header");
          192 
          193         if(get4(bin) != ZECHeader)
          194                 sysfatal("bad magic number on directory");
          195 
          196         get2(bin);
          197         get2(bin);
          198         get2(bin);
          199         entries = get2(bin);
          200         get4(bin);
          201         off = get4(bin);
          202         zclen = get2(bin);
          203         while(zclen-- > 0)
          204                 get1(bin);
          205 
          206         if(Bseek(bin, off, 0) != off)
          207                 sysfatal("can't seek to contents");
          208 
          209         return entries;
          210 }
          211 
          212 
          213 static int
          214 header(Biobuf *bin, ZipHead *zh)
          215 {
          216         ulong v;
          217         int flen, xlen;
          218 
          219         v = get4(bin);
          220         if(v != ZHeader){
          221                 if(v == ZCHeader)
          222                         return 0;
          223                 sysfatal("bad magic on local header");
          224         }
          225         zh->extvers = get1(bin);
          226         zh->extos = get1(bin);
          227         zh->flags = get2(bin);
          228         zh->meth = get2(bin);
          229         zh->modtime = get2(bin);
          230         zh->moddate = get2(bin);
          231         zh->crc = get4(bin);
          232         zh->csize = get4(bin);
          233         zh->uncsize = get4(bin);
          234         flen = get2(bin);
          235         xlen = get2(bin);
          236 
          237         zh->file = getname(bin, flen);
          238 
          239         while(xlen-- > 0)
          240                 get1(bin);
          241         return 1;
          242 }
          243 
          244 static int
          245 cheader(Biobuf *bin, ZipHead *zh)
          246 {
          247         ulong v;
          248         int flen, xlen, fclen;
          249 
          250         v = get4(bin);
          251         if(v != ZCHeader){
          252                 if(v == ZECHeader)
          253                         return 0;
          254                 sysfatal("bad magic number in file");
          255         }
          256         zh->madevers = get1(bin);
          257         zh->madeos = get1(bin);
          258         zh->extvers = get1(bin);
          259         zh->extos = get1(bin);
          260         zh->flags = get2(bin);
          261         zh->meth = get2(bin);
          262         zh->modtime = get2(bin);
          263         zh->moddate = get2(bin);
          264         zh->crc = get4(bin);
          265         zh->csize = get4(bin);
          266         zh->uncsize = get4(bin);
          267         flen = get2(bin);
          268         xlen = get2(bin);
          269         fclen = get2(bin);
          270         get2(bin);                /* disk number start */
          271         zh->iattr = get2(bin);        /* 1 == is-text-file */
          272         zh->eattr = get4(bin);        /* 1 == readonly-file */
          273         zh->off = get4(bin);
          274 
          275         zh->file = getname(bin, flen);
          276 
          277         while(xlen-- > 0)
          278                 get1(bin);
          279 
          280         while(fclen-- > 0)
          281                 get1(bin);
          282 
          283         return 1;
          284 }
          285 
          286 static int
          287 blwrite(void *vb, void *buf, int n)
          288 {
          289         Block *b = vb;
          290         if(n > b->limit - b->pos)
          291                 n = b->limit - b->pos;
          292         memmove(b->pos, buf, n);
          293         b->pos += n;
          294         return n;
          295 }
          296 
          297 /*
          298 static void
          299 trailer(Biobuf *bin, ZipHead *zh)
          300 {
          301         if(zh->flags & ZTrailInfo){
          302                 zh->crc = get4(bin);
          303                 zh->csize = get4(bin);
          304                 zh->uncsize = get4(bin);
          305         }
          306 }
          307 */
          308 
          309 static char*
          310 getname(Biobuf *bin, int len)
          311 {
          312         char *s;
          313         int i, c;
          314 
          315         s = emalloc(len + 1);
          316         for(i = 0; i < len; i++){
          317                 c = get1(bin);
          318                 if(FORCE_LOWER)
          319                         c = tolower(c);
          320                 s[i] = c;
          321         }
          322         s[i] = '\0';
          323         return s;
          324 }
          325 
          326 
          327 static ulong
          328 get4(Biobuf *b)
          329 {
          330         ulong v;
          331         int i, c;
          332 
          333         v = 0;
          334         for(i = 0; i < 4; i++){
          335                 c = Bgetc(b);
          336                 if(c < 0)
          337                         sysfatal("unexpected eof");
          338                 v |= c << (i * 8);
          339         }
          340         return v;
          341 }
          342 
          343 static int
          344 get2(Biobuf *b)
          345 {
          346         int i, c, v;
          347 
          348         v = 0;
          349         for(i = 0; i < 2; i++){
          350                 c = Bgetc(b);
          351                 if(c < 0)
          352                         sysfatal("unexpected eof");
          353                 v |= c << (i * 8);
          354         }
          355         return v;
          356 }
          357 
          358 static int
          359 get1(Biobuf *b)
          360 {
          361         int c;
          362 
          363         c = Bgetc(b);
          364         if(c < 0)
          365                 sysfatal("unexpected eof");
          366         return c;
          367 }
          368 
          369 static long
          370 msdos2time(int time, int date)
          371 {
          372         Tm tm;
          373 
          374         tm.hour = time >> 11;
          375         tm.min = (time >> 5) & 63;
          376         tm.sec = (time & 31) << 1;
          377         tm.year = 80 + (date >> 9);
          378         tm.mon = ((date >> 5) & 15) - 1;
          379         tm.mday = date & 31;
          380         tm.zone[0] = '\0';
          381         tm.yday = 0;
          382 
          383         return tm2sec(&tm);
          384 }