12 static int cheader(Biobuf *bin, ZipHead *zh);
13 static int copyout(int ofd, Biobuf *bin, long len);
14 static int crcwrite(void *ofd, void *buf, int n);
15 static int findCDir(Biobuf *bin, char *file);
16 static int get1(Biobuf *b);
17 static int get2(Biobuf *b);
18 static ulong get4(Biobuf *b);
19 static char *getname(Biobuf *b, int len);
20 static int header(Biobuf *bin, ZipHead *zh);
21 static long msdos2time(int time, int date);
22 static int sunzip(Biobuf *bin);
23 static int sunztable(Biobuf *bin);
24 static void trailer(Biobuf *bin, ZipHead *zh);
25 static int unzip(Biobuf *bin, char *file);
26 static int unzipEntry(Biobuf *bin, ZipHead *czh);
27 static int unztable(Biobuf *bin, char *file);
28 static int wantFile(char *file);
30 static void *emalloc(ulong);
31 static void error(char*, ...);
32 /* #pragma varargck argpos error 1 */
53 fprint(2, "usage: unzip [-tsv] [-f zipfile] [file ...]\n");
58 main(int argc, char *argv[])
61 int fd, ok, table, stream;
101 crctab = mkcrctab(ZCrcPoly);
104 sysfatal("inflateinit failed: %s\n", flateerr(ok));
107 Binit(&bin, 0, OREAD);
110 fd = open(zfile, OREAD);
112 sysfatal("can't open %s: %r", zfile);
113 Binit(&bin, fd, OREAD);
118 ok = sunztable(&bin);
120 ok = unztable(&bin, zfile);
125 ok = unzip(&bin, zfile);
128 exits(ok ? nil: "errors");
132 * print the table of contents from the "central directory structure"
135 unztable(Biobuf *bin, char *file)
138 int volatile entries;
140 entries = findCDir(bin, file);
145 print("%d items in the archive\n", entries);
146 while(entries-- > 0){
152 memset(&zh, 0, sizeof(zh));
153 if(!cheader(bin, &zh))
156 if(wantFile(zh.file)){
158 print("%-32s %10lud %s", zh.file, zh.uncsize, ctime(msdos2time(zh.modtime, zh.moddate)));
160 print("%s\n", zh.file);
163 print("\tmade by os %d vers %d.%d\n", zh.madeos, zh.madevers/10, zh.madevers % 10);
164 print("\textract by os %d vers %d.%d\n", zh.extos, zh.extvers/10, zh.extvers % 10);
165 print("\tflags %x\n", zh.flags);
166 print("\tmethod %d\n", zh.meth);
167 print("\tmod time %d\n", zh.modtime);
168 print("\tmod date %d\n", zh.moddate);
169 print("\tcrc %lux\n", zh.crc);
170 print("\tcompressed size %lud\n", zh.csize);
171 print("\tuncompressed size %lud\n", zh.uncsize);
172 print("\tinternal attributes %ux\n", zh.iattr);
173 print("\texternal attributes %lux\n", zh.eattr);
174 print("\tstarts at %ld\n", zh.off);
186 * print the "local file header" table of contents
189 sunztable(Biobuf *bin)
193 ulong hcrc, hcsize, huncsize;
203 memset(&zh, 0, sizeof(zh));
204 if(!header(bin, &zh))
209 huncsize = zh.uncsize;
217 if(!copyout(-1, bin, zh.csize))
218 error("reading data for %s failed: %r", zh.file);
219 }else if(zh.meth == 8){
221 err = inflate((void*)-1, crcwrite, bin, (int(*)(void*))Bgetc);
223 error("inflate %s failed: %s", zh.file, flateerr(err));
224 rlen = Boffset(bin) - off;
226 error("can't handle compression method %d for %s", zh.meth, zh.file);
230 if(wantFile(zh.file)){
232 print("%-32s %10lud %s", zh.file, zh.uncsize, ctime(msdos2time(zh.modtime, zh.moddate)));
234 print("%s\n", zh.file);
237 print("\textract by os %d vers %d.%d\n", zh.extos, zh.extvers / 10, zh.extvers % 10);
238 print("\tflags %x\n", zh.flags);
239 print("\tmethod %d\n", zh.meth);
240 print("\tmod time %d\n", zh.modtime);
241 print("\tmod date %d\n", zh.moddate);
242 print("\tcrc %lux\n", zh.crc);
243 print("\tcompressed size %lud\n", zh.csize);
244 print("\tuncompressed size %lud\n", zh.uncsize);
245 if((zh.flags & ZTrailInfo) && (hcrc || hcsize || huncsize)){
246 print("\theader crc %lux\n", zh.crc);
247 print("\theader compressed size %lud\n", zh.csize);
248 print("\theader uncompressed size %lud\n", zh.uncsize);
254 error("crc mismatch for %s", zh.file);
255 if(zh.uncsize != wlen)
256 error("output size mismatch for %s", zh.file);
258 error("input size mismatch for %s", zh.file);
267 * extract files using the info in the central directory structure
270 unzip(Biobuf *bin, char *file)
274 int volatile ok, eok, entries;
276 entries = findCDir(bin, file);
281 while(entries-- > 0){
286 memset(&zh, 0, sizeof(zh));
287 if(!cheader(bin, &zh))
292 if(wantFile(zh.file)){
293 if(Bseek(bin, zh.off, 0) < 0){
294 fprint(2, "unzip: can't seek to start of %s, skipping\n", zh.file);
297 eok = unzipEntry(bin, &zh);
299 fprint(2, "unzip: skipping %s\n", zh.file);
308 if(Bseek(bin, off, 0) < 0){
309 fprint(2, "unzip: can't seek to start of next entry, terminating extraction\n");
318 * extract files using the info the "local file headers"
326 eok = unzipEntry(bin, nil);
339 if (access(s, AEXIST) == 0)
341 f = create(s, OREAD, DMDIR | 0777);
353 while (!done && (p = strchr(p + 1, '/')) != nil) {
355 done = (access(s, AEXIST) < 0 && makedir(s) < 0);
361 * extracts a single entry from a zip file
362 * czh is the optional corresponding central directory entry
365 unzipEntry(Biobuf *bin, ZipHead *czh)
371 int fd, isdir, ok, err;
380 memset(&zh, 0, sizeof(zh));
381 if(!header(bin, &zh))
388 if(wantFile(zh.file)){
390 fprint(2, "extracting %s\n", zh.file);
392 if(czh != nil && czh->extos == ZDos){
393 isdir = czh->eattr & ZDDir;
394 if(isdir && zh.uncsize != 0)
395 fprint(2, "unzip: ignoring directory data for %s\n", zh.file);
397 if(zh.meth == 0 && zh.uncsize == 0){
398 p = strchr(zh.file, '\0');
399 if(p > zh.file && p[-1] == '/')
407 fd = create(zh.file, OREAD, DMDIR | 0775);
410 fd = create(zh.file, OREAD, DMDIR | 0775);
413 d = dirstat(zh.file);
414 if(d == nil || (d->mode & DMDIR) != DMDIR){
415 fprint(2, "unzip: can't create directory %s: %r\n", zh.file);
421 fd = create(zh.file, OWRITE, 0664);
424 fd = create(zh.file, OWRITE, 0664);
427 fprint(2, "unzip: can't create %s: %r\n", zh.file);
440 if(!copyout(fd, bin, zh.csize))
441 error("copying data for %s failed: %r", zh.file);
442 }else if(zh.meth == 8){
444 err = inflate((void*)fd, crcwrite, bin, (int(*)(void*))Bgetc);
446 error("inflate failed: %s", flateerr(err));
447 rlen = Boffset(bin) - off;
449 error("can't handle compression method %d for %s", zh.meth, zh.file);
454 error("crc mismatch for %s", zh.file);
455 if(zh.uncsize != wlen)
456 error("output size mismatch for %s", zh.file);
458 error("input size mismatch for %s", zh.file);
463 if(fd >= 0 && !stdout){
467 d->mtime = msdos2time(zh.modtime, zh.moddate);
485 for(i = 0; i < nwant; i++){
486 if(strcmp(want[i], file) == 0)
489 if(strncmp(want[i], file, n) == 0 && file[n] == '/')
496 * find the start of the central directory
497 * returns the number of entries in the directory,
498 * or -1 if there was an error
501 findCDir(Biobuf *bin, char *file)
505 int entries, zclen, dn, ds, de;
507 ecoff = Bseek(bin, -ZECHeadSize, 2);
509 fprint(2, "unzip: can't seek to contents of %s; try adding -s\n", file);
515 if(get4(bin) != ZECHeader){
516 fprint(2, "unzip: bad magic number for contents of %s\n", file);
530 print("table starts at %ld for %ld bytes\n", off, size);
531 if(ecoff - size != off)
532 print("\ttable should start at %lld-%ld=%lld\n", ecoff, size, ecoff-size);
533 if(dn || ds || de != entries)
534 print("\tcurrent disk=%d start disk=%d table entries on this disk=%d\n", dn, ds, de);
537 if(Bseek(bin, off, 0) != off){
538 fprint(2, "unzip: can't seek to start of contents of %s\n", file);
546 cheader(Biobuf *bin, ZipHead *zh)
549 int flen, xlen, fclen;
555 error("bad magic number %lux", v);
557 zh->madevers = get1(bin);
558 zh->madeos = get1(bin);
559 zh->extvers = get1(bin);
560 zh->extos = get1(bin);
561 zh->flags = get2(bin);
562 zh->meth = get2(bin);
563 zh->modtime = get2(bin);
564 zh->moddate = get2(bin);
566 zh->csize = get4(bin);
567 zh->uncsize = get4(bin);
571 get2(bin); /* disk number start */
572 zh->iattr = get2(bin);
573 zh->eattr = get4(bin);
576 zh->file = getname(bin, flen);
588 header(Biobuf *bin, ZipHead *zh)
597 error("bad magic number %lux at %lld", v, Boffset(bin)-4);
599 zh->extvers = get1(bin);
600 zh->extos = get1(bin);
601 zh->flags = get2(bin);
602 zh->meth = get2(bin);
603 zh->modtime = get2(bin);
604 zh->moddate = get2(bin);
606 zh->csize = get4(bin);
607 zh->uncsize = get4(bin);
611 zh->file = getname(bin, flen);
620 trailer(Biobuf *bin, ZipHead *zh)
622 if(zh->flags & ZTrailInfo){
624 zh->csize = get4(bin);
625 zh->uncsize = get4(bin);
630 getname(Biobuf *bin, int len)
635 s = emalloc(len + 1);
636 for(i = 0; i < len; i++){
647 crcwrite(void *out, void *buf, int n)
652 crc = blockcrc(crctab, crc, buf, n);
656 nw = write(fd, buf, n);
663 copyout(int ofd, Biobuf *bin, long len)
668 for(; len > 0; len -= n){
672 n = Bread(bin, buf, n);
676 if(crcwrite((void*)ofd, buf, n) != n)
689 for(i = 0; i < 4; i++){
692 error("unexpected eof reading file information");
704 for(i = 0; i < 2; i++){
707 error("unexpected eof reading file information");
720 error("unexpected eof reading file information");
725 msdos2time(int time, int date)
729 tm.hour = time >> 11;
730 tm.min = (time >> 5) & 63;
731 tm.sec = (time & 31) << 1;
732 tm.year = 80 + (date >> 9);
733 tm.mon = ((date >> 5) & 15) - 1;
748 sysfatal("out of memory");
753 error(char *fmt, ...)
757 fprint(2, "unzip: ");
759 vfprint(2, fmt, arg);
764 fprint(2, "unzip: removing output file %s\n", delfile);