17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
480ee5cbfSDavid du Colombier #include <flate.h>
57dd7cddfSDavid du Colombier #include "zip.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier enum
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier HeadAlloc = 64,
107dd7cddfSDavid du Colombier };
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier static void zip(Biobuf *bout, char *file, int stdout);
137dd7cddfSDavid du Colombier static void zipDir(Biobuf *bout, int fd, ZipHead *zh, int stdout);
147dd7cddfSDavid du Colombier static int crcread(void *fd, void *buf, int n);
157dd7cddfSDavid du Colombier static int zwrite(void *bout, void *buf, int n);
167dd7cddfSDavid du Colombier static void put4(Biobuf *b, ulong v);
177dd7cddfSDavid du Colombier static void put2(Biobuf *b, int v);
187dd7cddfSDavid du Colombier static void put1(Biobuf *b, int v);
197dd7cddfSDavid du Colombier static void header(Biobuf *bout, ZipHead *zh);
207dd7cddfSDavid du Colombier static void trailer(Biobuf *bout, ZipHead *zh, vlong off);
217dd7cddfSDavid du Colombier static void putCDir(Biobuf *bout);
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier static void error(char*, ...);
247dd7cddfSDavid du Colombier #pragma varargck argpos error 1
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier static Biobuf bout;
277dd7cddfSDavid du Colombier static ulong crc;
2880ee5cbfSDavid du Colombier static ulong *crctab;
297dd7cddfSDavid du Colombier static int debug;
307dd7cddfSDavid du Colombier static int eof;
317dd7cddfSDavid du Colombier static int level;
327dd7cddfSDavid du Colombier static int nzheads;
337dd7cddfSDavid du Colombier static ulong totr;
347dd7cddfSDavid du Colombier static ulong totw;
357dd7cddfSDavid du Colombier static int verbose;
367dd7cddfSDavid du Colombier static int zhalloc;
377dd7cddfSDavid du Colombier static ZipHead *zheads;
387dd7cddfSDavid du Colombier static jmp_buf zjmp;
397dd7cddfSDavid du Colombier
407dd7cddfSDavid du Colombier void
usage(void)417dd7cddfSDavid du Colombier usage(void)
427dd7cddfSDavid du Colombier {
437dd7cddfSDavid du Colombier fprint(2, "usage: zip [-vD] [-1-9] [-f zipfile] file ...\n");
447dd7cddfSDavid du Colombier exits("usage");
457dd7cddfSDavid du Colombier }
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier void
main(int argc,char * argv[])487dd7cddfSDavid du Colombier main(int argc, char *argv[])
497dd7cddfSDavid du Colombier {
507dd7cddfSDavid du Colombier char *zfile;
5180ee5cbfSDavid du Colombier int i, fd, err;
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier zfile = nil;
547dd7cddfSDavid du Colombier level = 6;
557dd7cddfSDavid du Colombier ARGBEGIN{
567dd7cddfSDavid du Colombier case 'D':
577dd7cddfSDavid du Colombier debug++;
587dd7cddfSDavid du Colombier break;
597dd7cddfSDavid du Colombier case 'f':
607dd7cddfSDavid du Colombier zfile = ARGF();
617dd7cddfSDavid du Colombier if(zfile == nil)
627dd7cddfSDavid du Colombier usage();
637dd7cddfSDavid du Colombier break;
647dd7cddfSDavid du Colombier case 'v':
657dd7cddfSDavid du Colombier verbose++;
667dd7cddfSDavid du Colombier break;
677dd7cddfSDavid du Colombier case '1': case '2': case '3': case '4':
687dd7cddfSDavid du Colombier case '5': case '6': case '7': case '8': case '9':
697dd7cddfSDavid du Colombier level = ARGC() - '0';
707dd7cddfSDavid du Colombier break;
717dd7cddfSDavid du Colombier default:
727dd7cddfSDavid du Colombier usage();
737dd7cddfSDavid du Colombier break;
747dd7cddfSDavid du Colombier }ARGEND
757dd7cddfSDavid du Colombier
767dd7cddfSDavid du Colombier if(argc == 0)
777dd7cddfSDavid du Colombier usage();
787dd7cddfSDavid du Colombier
7980ee5cbfSDavid du Colombier crctab = mkcrctab(ZCrcPoly);
8080ee5cbfSDavid du Colombier err = deflateinit();
8180ee5cbfSDavid du Colombier if(err != FlateOk)
82*14cc0f53SDavid du Colombier sysfatal("deflateinit failed: %s", flateerr(err));
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier if(zfile == nil)
857dd7cddfSDavid du Colombier fd = 1;
867dd7cddfSDavid du Colombier else{
877dd7cddfSDavid du Colombier fd = create(zfile, OWRITE, 0664);
887dd7cddfSDavid du Colombier if(fd < 0)
89*14cc0f53SDavid du Colombier sysfatal("can't create %s: %r", zfile);
907dd7cddfSDavid du Colombier }
917dd7cddfSDavid du Colombier Binit(&bout, fd, OWRITE);
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier if(setjmp(zjmp)){
947dd7cddfSDavid du Colombier if(zfile != nil){
957dd7cddfSDavid du Colombier fprint(2, "zip: removing output file %s\n", zfile);
967dd7cddfSDavid du Colombier remove(zfile);
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier exits("errors");
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier for(i = 0; i < argc; i++)
1027dd7cddfSDavid du Colombier zip(&bout, argv[i], zfile == nil);
1037dd7cddfSDavid du Colombier
1047dd7cddfSDavid du Colombier putCDir(&bout);
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier exits(nil);
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier static void
zip(Biobuf * bout,char * file,int stdout)1107dd7cddfSDavid du Colombier zip(Biobuf *bout, char *file, int stdout)
1117dd7cddfSDavid du Colombier {
1127dd7cddfSDavid du Colombier Tm *t;
1137dd7cddfSDavid du Colombier ZipHead *zh;
1149a747e4fSDavid du Colombier Dir *dir;
1157dd7cddfSDavid du Colombier vlong off;
11680ee5cbfSDavid du Colombier int fd, err;
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier fd = open(file, OREAD);
1197dd7cddfSDavid du Colombier if(fd < 0)
1207dd7cddfSDavid du Colombier error("can't open %s: %r", file);
1219a747e4fSDavid du Colombier dir = dirfstat(fd);
1229a747e4fSDavid du Colombier if(dir == nil)
1237dd7cddfSDavid du Colombier error("can't stat %s: %r", file);
1247dd7cddfSDavid du Colombier
1257dd7cddfSDavid du Colombier /*
1267dd7cddfSDavid du Colombier * create the header
1277dd7cddfSDavid du Colombier */
1287dd7cddfSDavid du Colombier if(nzheads >= zhalloc){
1297dd7cddfSDavid du Colombier zhalloc += HeadAlloc;
1307dd7cddfSDavid du Colombier zheads = realloc(zheads, zhalloc * sizeof(ZipHead));
1317dd7cddfSDavid du Colombier if(zheads == nil)
1327dd7cddfSDavid du Colombier error("out of memory");
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier zh = &zheads[nzheads++];
1357dd7cddfSDavid du Colombier zh->madeos = ZDos;
1367dd7cddfSDavid du Colombier zh->madevers = (2 * 10) + 0;
1377dd7cddfSDavid du Colombier zh->extos = ZDos;
1387dd7cddfSDavid du Colombier zh->extvers = (2 * 10) + 0;
1397dd7cddfSDavid du Colombier
1409a747e4fSDavid du Colombier t = localtime(dir->mtime);
1417dd7cddfSDavid du Colombier zh->modtime = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
1427dd7cddfSDavid du Colombier zh->moddate = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
1437dd7cddfSDavid du Colombier
1447dd7cddfSDavid du Colombier zh->flags = 0;
1457dd7cddfSDavid du Colombier zh->crc = 0;
1467dd7cddfSDavid du Colombier zh->csize = 0;
1477dd7cddfSDavid du Colombier zh->uncsize = 0;
1487dd7cddfSDavid du Colombier zh->file = strdup(file);
1497dd7cddfSDavid du Colombier if(zh->file == nil)
1507dd7cddfSDavid du Colombier error("out of memory");
1517dd7cddfSDavid du Colombier zh->iattr = 0;
1527dd7cddfSDavid du Colombier zh->eattr = ZDArch;
1539a747e4fSDavid du Colombier if((dir->mode & 0700) == 0)
1547dd7cddfSDavid du Colombier zh->eattr |= ZDROnly;
1557dd7cddfSDavid du Colombier zh->off = Boffset(bout);
1567dd7cddfSDavid du Colombier
1579a747e4fSDavid du Colombier if(dir->mode & DMDIR){
1587dd7cddfSDavid du Colombier zh->eattr |= ZDDir;
1597dd7cddfSDavid du Colombier zh->meth = 0;
1607dd7cddfSDavid du Colombier zipDir(bout, fd, zh, stdout);
1617dd7cddfSDavid du Colombier }else{
1627dd7cddfSDavid du Colombier zh->meth = 8;
1637dd7cddfSDavid du Colombier if(stdout)
1647dd7cddfSDavid du Colombier zh->flags |= ZTrailInfo;
1657dd7cddfSDavid du Colombier off = Boffset(bout);
1667dd7cddfSDavid du Colombier header(bout, zh);
1677dd7cddfSDavid du Colombier
1687dd7cddfSDavid du Colombier crc = 0;
1697dd7cddfSDavid du Colombier eof = 0;
1707dd7cddfSDavid du Colombier totr = 0;
1717dd7cddfSDavid du Colombier totw = 0;
17280ee5cbfSDavid du Colombier err = deflate(bout, zwrite, (void*)fd, crcread, level, debug);
17380ee5cbfSDavid du Colombier if(err != FlateOk)
17480ee5cbfSDavid du Colombier error("deflate failed: %s: %r", flateerr(err));
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier zh->csize = totw;
1777dd7cddfSDavid du Colombier zh->uncsize = totr;
1787dd7cddfSDavid du Colombier zh->crc = crc;
1797dd7cddfSDavid du Colombier trailer(bout, zh, off);
1807dd7cddfSDavid du Colombier }
1817dd7cddfSDavid du Colombier close(fd);
1829a747e4fSDavid du Colombier free(dir);
1837dd7cddfSDavid du Colombier }
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier static void
zipDir(Biobuf * bout,int fd,ZipHead * zh,int stdout)1867dd7cddfSDavid du Colombier zipDir(Biobuf *bout, int fd, ZipHead *zh, int stdout)
1877dd7cddfSDavid du Colombier {
1889a747e4fSDavid du Colombier Dir *dirs;
1897dd7cddfSDavid du Colombier char *file, *pfile;
1907dd7cddfSDavid du Colombier int i, nf, nd;
1917dd7cddfSDavid du Colombier
1927dd7cddfSDavid du Colombier nf = strlen(zh->file) + 1;
1937dd7cddfSDavid du Colombier if(strcmp(zh->file, ".") == 0){
1947dd7cddfSDavid du Colombier nzheads--;
1957dd7cddfSDavid du Colombier free(zh->file);
1967dd7cddfSDavid du Colombier pfile = "";
1977dd7cddfSDavid du Colombier nf = 1;
1987dd7cddfSDavid du Colombier }else{
1997dd7cddfSDavid du Colombier nf++;
2007dd7cddfSDavid du Colombier pfile = malloc(nf);
2017dd7cddfSDavid du Colombier if(pfile == nil)
2027dd7cddfSDavid du Colombier error("out of memory");
2037dd7cddfSDavid du Colombier snprint(pfile, nf, "%s/", zh->file);
2047dd7cddfSDavid du Colombier free(zh->file);
2057dd7cddfSDavid du Colombier zh->file = pfile;
2067dd7cddfSDavid du Colombier header(bout, zh);
2077dd7cddfSDavid du Colombier }
2087dd7cddfSDavid du Colombier
2099a747e4fSDavid du Colombier nf += 256; /* plenty of room */
2107dd7cddfSDavid du Colombier file = malloc(nf);
2117dd7cddfSDavid du Colombier if(file == nil)
2127dd7cddfSDavid du Colombier error("out of memory");
213d9306527SDavid du Colombier while((nd = dirread(fd, &dirs)) > 0){
2147dd7cddfSDavid du Colombier for(i = 0; i < nd; i++){
2157dd7cddfSDavid du Colombier snprint(file, nf, "%s%s", pfile, dirs[i].name);
2167dd7cddfSDavid du Colombier zip(bout, file, stdout);
2177dd7cddfSDavid du Colombier }
2189a747e4fSDavid du Colombier free(dirs);
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier
2227dd7cddfSDavid du Colombier static void
header(Biobuf * bout,ZipHead * zh)2237dd7cddfSDavid du Colombier header(Biobuf *bout, ZipHead *zh)
2247dd7cddfSDavid du Colombier {
2257dd7cddfSDavid du Colombier int flen;
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier if(verbose)
2287dd7cddfSDavid du Colombier fprint(2, "adding %s\n", zh->file);
2297dd7cddfSDavid du Colombier put4(bout, ZHeader);
2307dd7cddfSDavid du Colombier put1(bout, zh->extvers);
2317dd7cddfSDavid du Colombier put1(bout, zh->extos);
2327dd7cddfSDavid du Colombier put2(bout, zh->flags);
2337dd7cddfSDavid du Colombier put2(bout, zh->meth);
2347dd7cddfSDavid du Colombier put2(bout, zh->modtime);
2357dd7cddfSDavid du Colombier put2(bout, zh->moddate);
2367dd7cddfSDavid du Colombier put4(bout, zh->crc);
2377dd7cddfSDavid du Colombier put4(bout, zh->csize);
2387dd7cddfSDavid du Colombier put4(bout, zh->uncsize);
2397dd7cddfSDavid du Colombier flen = strlen(zh->file);
2407dd7cddfSDavid du Colombier put2(bout, flen);
2417dd7cddfSDavid du Colombier put2(bout, 0);
2427dd7cddfSDavid du Colombier if(Bwrite(bout, zh->file, flen) != flen)
2437dd7cddfSDavid du Colombier error("write error");
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier
2467dd7cddfSDavid du Colombier static void
trailer(Biobuf * bout,ZipHead * zh,vlong off)2477dd7cddfSDavid du Colombier trailer(Biobuf *bout, ZipHead *zh, vlong off)
2487dd7cddfSDavid du Colombier {
2497dd7cddfSDavid du Colombier vlong coff;
2507dd7cddfSDavid du Colombier
2517dd7cddfSDavid du Colombier coff = -1;
2527dd7cddfSDavid du Colombier if(!(zh->flags & ZTrailInfo)){
2537dd7cddfSDavid du Colombier coff = Boffset(bout);
2547dd7cddfSDavid du Colombier if(Bseek(bout, off + ZHeadCrc, 0) < 0)
2557dd7cddfSDavid du Colombier error("can't seek in archive");
2567dd7cddfSDavid du Colombier }
2577dd7cddfSDavid du Colombier put4(bout, zh->crc);
2587dd7cddfSDavid du Colombier put4(bout, zh->csize);
2597dd7cddfSDavid du Colombier put4(bout, zh->uncsize);
2607dd7cddfSDavid du Colombier if(!(zh->flags & ZTrailInfo)){
2617dd7cddfSDavid du Colombier if(Bseek(bout, coff, 0) < 0)
2627dd7cddfSDavid du Colombier error("can't seek in archive");
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier
2667dd7cddfSDavid du Colombier static void
cheader(Biobuf * bout,ZipHead * zh)2677dd7cddfSDavid du Colombier cheader(Biobuf *bout, ZipHead *zh)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier int flen;
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier put4(bout, ZCHeader);
2727dd7cddfSDavid du Colombier put1(bout, zh->madevers);
2737dd7cddfSDavid du Colombier put1(bout, zh->madeos);
2747dd7cddfSDavid du Colombier put1(bout, zh->extvers);
2757dd7cddfSDavid du Colombier put1(bout, zh->extos);
2767dd7cddfSDavid du Colombier put2(bout, zh->flags & ~ZTrailInfo);
2777dd7cddfSDavid du Colombier put2(bout, zh->meth);
2787dd7cddfSDavid du Colombier put2(bout, zh->modtime);
2797dd7cddfSDavid du Colombier put2(bout, zh->moddate);
2807dd7cddfSDavid du Colombier put4(bout, zh->crc);
2817dd7cddfSDavid du Colombier put4(bout, zh->csize);
2827dd7cddfSDavid du Colombier put4(bout, zh->uncsize);
2837dd7cddfSDavid du Colombier flen = strlen(zh->file);
2847dd7cddfSDavid du Colombier put2(bout, flen);
2857dd7cddfSDavid du Colombier put2(bout, 0);
2867dd7cddfSDavid du Colombier put2(bout, 0);
2877dd7cddfSDavid du Colombier put2(bout, 0);
2887dd7cddfSDavid du Colombier put2(bout, zh->iattr);
2897dd7cddfSDavid du Colombier put4(bout, zh->eattr);
2907dd7cddfSDavid du Colombier put4(bout, zh->off);
2917dd7cddfSDavid du Colombier if(Bwrite(bout, zh->file, flen) != flen)
2927dd7cddfSDavid du Colombier error("write error");
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier
2957dd7cddfSDavid du Colombier static void
putCDir(Biobuf * bout)2967dd7cddfSDavid du Colombier putCDir(Biobuf *bout)
2977dd7cddfSDavid du Colombier {
2987dd7cddfSDavid du Colombier vlong hoff, ecoff;
2997dd7cddfSDavid du Colombier int i;
3007dd7cddfSDavid du Colombier
3017dd7cddfSDavid du Colombier hoff = Boffset(bout);
3027dd7cddfSDavid du Colombier
3037dd7cddfSDavid du Colombier for(i = 0; i < nzheads; i++)
3047dd7cddfSDavid du Colombier cheader(bout, &zheads[i]);
3057dd7cddfSDavid du Colombier
3067dd7cddfSDavid du Colombier ecoff = Boffset(bout);
3077dd7cddfSDavid du Colombier
3087dd7cddfSDavid du Colombier if(nzheads >= (1 << 16))
3097dd7cddfSDavid du Colombier error("too many entries in zip file: max %d", (1 << 16) - 1);
3107dd7cddfSDavid du Colombier put4(bout, ZECHeader);
3117dd7cddfSDavid du Colombier put2(bout, 0);
3127dd7cddfSDavid du Colombier put2(bout, 0);
3137dd7cddfSDavid du Colombier put2(bout, nzheads);
3147dd7cddfSDavid du Colombier put2(bout, nzheads);
3157dd7cddfSDavid du Colombier put4(bout, ecoff - hoff);
3167dd7cddfSDavid du Colombier put4(bout, hoff);
3177dd7cddfSDavid du Colombier put2(bout, 0);
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier
3207dd7cddfSDavid du Colombier static int
crcread(void * fd,void * buf,int n)3217dd7cddfSDavid du Colombier crcread(void *fd, void *buf, int n)
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier int nr, m;
3247dd7cddfSDavid du Colombier
3257dd7cddfSDavid du Colombier nr = 0;
3267dd7cddfSDavid du Colombier for(; !eof && n > 0; n -= m){
32774f16c81SDavid du Colombier m = read((int)(uintptr)fd, (char*)buf+nr, n);
3287dd7cddfSDavid du Colombier if(m <= 0){
3297dd7cddfSDavid du Colombier eof = 1;
33080ee5cbfSDavid du Colombier if(m < 0)
33180ee5cbfSDavid du Colombier {
33280ee5cbfSDavid du Colombier fprint(2, "input error %r\n");
33380ee5cbfSDavid du Colombier return -1;
33480ee5cbfSDavid du Colombier }
3357dd7cddfSDavid du Colombier break;
3367dd7cddfSDavid du Colombier }
3377dd7cddfSDavid du Colombier nr += m;
3387dd7cddfSDavid du Colombier }
33980ee5cbfSDavid du Colombier crc = blockcrc(crctab, crc, buf, nr);
3407dd7cddfSDavid du Colombier totr += nr;
3417dd7cddfSDavid du Colombier return nr;
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier
3447dd7cddfSDavid du Colombier static int
zwrite(void * bout,void * buf,int n)3457dd7cddfSDavid du Colombier zwrite(void *bout, void *buf, int n)
3467dd7cddfSDavid du Colombier {
3477dd7cddfSDavid du Colombier if(n != Bwrite(bout, buf, n)){
3487dd7cddfSDavid du Colombier eof = 1;
3497dd7cddfSDavid du Colombier return -1;
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier totw += n;
3527dd7cddfSDavid du Colombier return n;
3537dd7cddfSDavid du Colombier }
3547dd7cddfSDavid du Colombier
3557dd7cddfSDavid du Colombier static void
put4(Biobuf * b,ulong v)3567dd7cddfSDavid du Colombier put4(Biobuf *b, ulong v)
3577dd7cddfSDavid du Colombier {
3587dd7cddfSDavid du Colombier int i;
3597dd7cddfSDavid du Colombier
3607dd7cddfSDavid du Colombier for(i = 0; i < 4; i++){
3617dd7cddfSDavid du Colombier if(Bputc(b, v) < 0)
3627dd7cddfSDavid du Colombier error("write error");
3637dd7cddfSDavid du Colombier v >>= 8;
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier }
3667dd7cddfSDavid du Colombier
3677dd7cddfSDavid du Colombier static void
put2(Biobuf * b,int v)3687dd7cddfSDavid du Colombier put2(Biobuf *b, int v)
3697dd7cddfSDavid du Colombier {
3707dd7cddfSDavid du Colombier int i;
3717dd7cddfSDavid du Colombier
3727dd7cddfSDavid du Colombier for(i = 0; i < 2; i++){
3737dd7cddfSDavid du Colombier if(Bputc(b, v) < 0)
3747dd7cddfSDavid du Colombier error("write error");
3757dd7cddfSDavid du Colombier v >>= 8;
3767dd7cddfSDavid du Colombier }
3777dd7cddfSDavid du Colombier }
3787dd7cddfSDavid du Colombier
3797dd7cddfSDavid du Colombier static void
put1(Biobuf * b,int v)3807dd7cddfSDavid du Colombier put1(Biobuf *b, int v)
3817dd7cddfSDavid du Colombier {
3827dd7cddfSDavid du Colombier if(Bputc(b, v)< 0)
3837dd7cddfSDavid du Colombier error("unexpected eof reading file information");
3847dd7cddfSDavid du Colombier }
3857dd7cddfSDavid du Colombier
3867dd7cddfSDavid du Colombier static void
error(char * fmt,...)3877dd7cddfSDavid du Colombier error(char *fmt, ...)
3887dd7cddfSDavid du Colombier {
3897dd7cddfSDavid du Colombier va_list arg;
3907dd7cddfSDavid du Colombier
3919a747e4fSDavid du Colombier fprint(2, "zip: ");
3927dd7cddfSDavid du Colombier va_start(arg, fmt);
3939a747e4fSDavid du Colombier vfprint(2, fmt, arg);
3947dd7cddfSDavid du Colombier va_end(arg);
3959a747e4fSDavid du Colombier fprint(2, "\n");
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier longjmp(zjmp, 1);
3987dd7cddfSDavid du Colombier }
399