123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <flate.h>
- #include "zip.h"
- enum
- {
- HeadAlloc = 64,
- };
- static void zip(Biobuf *bout, char *file, int stdout);
- static void zipDir(Biobuf *bout, int fd, ZipHead *zh, int stdout);
- static int crcread(void *fd, void *buf, int n);
- static int zwrite(void *bout, void *buf, int n);
- static void put4(Biobuf *b, ulong v);
- static void put2(Biobuf *b, int v);
- static void put1(Biobuf *b, int v);
- static void header(Biobuf *bout, ZipHead *zh);
- static void trailer(Biobuf *bout, ZipHead *zh, vlong off);
- static void putCDir(Biobuf *bout);
- static void error(char*, ...);
- #pragma varargck argpos error 1
- static Biobuf bout;
- static ulong crc;
- static ulong *crctab;
- static int debug;
- static int eof;
- static int level;
- static int nzheads;
- static ulong totr;
- static ulong totw;
- static int verbose;
- static int zhalloc;
- static ZipHead *zheads;
- static jmp_buf zjmp;
- void
- usage(void)
- {
- fprint(2, "usage: zip [-vD] [-1-9] [-f zipfile] file ...\n");
- exits("usage");
- }
- void
- main(int argc, char *argv[])
- {
- char *zfile;
- int i, fd, err;
- zfile = nil;
- level = 6;
- ARGBEGIN{
- case 'D':
- debug++;
- break;
- case 'f':
- zfile = ARGF();
- if(zfile == nil)
- usage();
- break;
- case 'v':
- verbose++;
- break;
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- level = ARGC() - '0';
- break;
- default:
- usage();
- break;
- }ARGEND
- if(argc == 0)
- usage();
- crctab = mkcrctab(ZCrcPoly);
- err = deflateinit();
- if(err != FlateOk)
- sysfatal("deflateinit failed: %s\n", flateerr(err));
- if(zfile == nil)
- fd = 1;
- else{
- fd = create(zfile, OWRITE, 0664);
- if(fd < 0)
- sysfatal("can't create %s: %r\n", zfile);
- }
- Binit(&bout, fd, OWRITE);
- if(setjmp(zjmp)){
- if(zfile != nil){
- fprint(2, "zip: removing output file %s\n", zfile);
- remove(zfile);
- }
- exits("errors");
- }
- for(i = 0; i < argc; i++)
- zip(&bout, argv[i], zfile == nil);
- putCDir(&bout);
- exits(nil);
- }
- static void
- zip(Biobuf *bout, char *file, int stdout)
- {
- Tm *t;
- ZipHead *zh;
- Dir *dir;
- vlong off;
- int fd, err;
- fd = open(file, OREAD);
- if(fd < 0)
- error("can't open %s: %r", file);
- dir = dirfstat(fd);
- if(dir == nil)
- error("can't stat %s: %r", file);
- /*
- * create the header
- */
- if(nzheads >= zhalloc){
- zhalloc += HeadAlloc;
- zheads = realloc(zheads, zhalloc * sizeof(ZipHead));
- if(zheads == nil)
- error("out of memory");
- }
- zh = &zheads[nzheads++];
- zh->madeos = ZDos;
- zh->madevers = (2 * 10) + 0;
- zh->extos = ZDos;
- zh->extvers = (2 * 10) + 0;
-
- t = localtime(dir->mtime);
- zh->modtime = (t->hour<<11) | (t->min<<5) | (t->sec>>1);
- zh->moddate = ((t->year-80)<<9) | ((t->mon+1)<<5) | t->mday;
- zh->flags = 0;
- zh->crc = 0;
- zh->csize = 0;
- zh->uncsize = 0;
- zh->file = strdup(file);
- if(zh->file == nil)
- error("out of memory");
- zh->iattr = 0;
- zh->eattr = ZDArch;
- if((dir->mode & 0700) == 0)
- zh->eattr |= ZDROnly;
- zh->off = Boffset(bout);
- if(dir->mode & DMDIR){
- zh->eattr |= ZDDir;
- zh->meth = 0;
- zipDir(bout, fd, zh, stdout);
- }else{
- zh->meth = 8;
- if(stdout)
- zh->flags |= ZTrailInfo;
- off = Boffset(bout);
- header(bout, zh);
- crc = 0;
- eof = 0;
- totr = 0;
- totw = 0;
- err = deflate(bout, zwrite, (void*)fd, crcread, level, debug);
- if(err != FlateOk)
- error("deflate failed: %s: %r", flateerr(err));
- zh->csize = totw;
- zh->uncsize = totr;
- zh->crc = crc;
- trailer(bout, zh, off);
- }
- close(fd);
- free(dir);
- }
- static void
- zipDir(Biobuf *bout, int fd, ZipHead *zh, int stdout)
- {
- Dir *dirs;
- char *file, *pfile;
- int i, nf, nd;
- nf = strlen(zh->file) + 1;
- if(strcmp(zh->file, ".") == 0){
- nzheads--;
- free(zh->file);
- pfile = "";
- nf = 1;
- }else{
- nf++;
- pfile = malloc(nf);
- if(pfile == nil)
- error("out of memory");
- snprint(pfile, nf, "%s/", zh->file);
- free(zh->file);
- zh->file = pfile;
- header(bout, zh);
- }
- nf += 256; /* plenty of room */
- file = malloc(nf);
- if(file == nil)
- error("out of memory");
- while((nd = dirread(fd, &dirs)) > 0){
- for(i = 0; i < nd; i++){
- snprint(file, nf, "%s%s", pfile, dirs[i].name);
- zip(bout, file, stdout);
- }
- free(dirs);
- }
- }
- static void
- header(Biobuf *bout, ZipHead *zh)
- {
- int flen;
- if(verbose)
- fprint(2, "adding %s\n", zh->file);
- put4(bout, ZHeader);
- put1(bout, zh->extvers);
- put1(bout, zh->extos);
- put2(bout, zh->flags);
- put2(bout, zh->meth);
- put2(bout, zh->modtime);
- put2(bout, zh->moddate);
- put4(bout, zh->crc);
- put4(bout, zh->csize);
- put4(bout, zh->uncsize);
- flen = strlen(zh->file);
- put2(bout, flen);
- put2(bout, 0);
- if(Bwrite(bout, zh->file, flen) != flen)
- error("write error");
- }
- static void
- trailer(Biobuf *bout, ZipHead *zh, vlong off)
- {
- vlong coff;
- coff = -1;
- if(!(zh->flags & ZTrailInfo)){
- coff = Boffset(bout);
- if(Bseek(bout, off + ZHeadCrc, 0) < 0)
- error("can't seek in archive");
- }
- put4(bout, zh->crc);
- put4(bout, zh->csize);
- put4(bout, zh->uncsize);
- if(!(zh->flags & ZTrailInfo)){
- if(Bseek(bout, coff, 0) < 0)
- error("can't seek in archive");
- }
- }
- static void
- cheader(Biobuf *bout, ZipHead *zh)
- {
- int flen;
- put4(bout, ZCHeader);
- put1(bout, zh->madevers);
- put1(bout, zh->madeos);
- put1(bout, zh->extvers);
- put1(bout, zh->extos);
- put2(bout, zh->flags & ~ZTrailInfo);
- put2(bout, zh->meth);
- put2(bout, zh->modtime);
- put2(bout, zh->moddate);
- put4(bout, zh->crc);
- put4(bout, zh->csize);
- put4(bout, zh->uncsize);
- flen = strlen(zh->file);
- put2(bout, flen);
- put2(bout, 0);
- put2(bout, 0);
- put2(bout, 0);
- put2(bout, zh->iattr);
- put4(bout, zh->eattr);
- put4(bout, zh->off);
- if(Bwrite(bout, zh->file, flen) != flen)
- error("write error");
- }
- static void
- putCDir(Biobuf *bout)
- {
- vlong hoff, ecoff;
- int i;
- hoff = Boffset(bout);
- for(i = 0; i < nzheads; i++)
- cheader(bout, &zheads[i]);
- ecoff = Boffset(bout);
- if(nzheads >= (1 << 16))
- error("too many entries in zip file: max %d", (1 << 16) - 1);
- put4(bout, ZECHeader);
- put2(bout, 0);
- put2(bout, 0);
- put2(bout, nzheads);
- put2(bout, nzheads);
- put4(bout, ecoff - hoff);
- put4(bout, hoff);
- put2(bout, 0);
- }
- static int
- crcread(void *fd, void *buf, int n)
- {
- int nr, m;
- nr = 0;
- for(; !eof && n > 0; n -= m){
- m = read((int)(uintptr)fd, (char*)buf+nr, n);
- if(m <= 0){
- eof = 1;
- if(m < 0)
- {
- fprint(2, "input error %r\n");
- return -1;
- }
- break;
- }
- nr += m;
- }
- crc = blockcrc(crctab, crc, buf, nr);
- totr += nr;
- return nr;
- }
- static int
- zwrite(void *bout, void *buf, int n)
- {
- if(n != Bwrite(bout, buf, n)){
- eof = 1;
- return -1;
- }
- totw += n;
- return n;
- }
- static void
- put4(Biobuf *b, ulong v)
- {
- int i;
- for(i = 0; i < 4; i++){
- if(Bputc(b, v) < 0)
- error("write error");
- v >>= 8;
- }
- }
- static void
- put2(Biobuf *b, int v)
- {
- int i;
- for(i = 0; i < 2; i++){
- if(Bputc(b, v) < 0)
- error("write error");
- v >>= 8;
- }
- }
- static void
- put1(Biobuf *b, int v)
- {
- if(Bputc(b, v)< 0)
- error("unexpected eof reading file information");
- }
- static void
- error(char *fmt, ...)
- {
- va_list arg;
- fprint(2, "zip: ");
- va_start(arg, fmt);
- vfprint(2, fmt, arg);
- va_end(arg);
- fprint(2, "\n");
- longjmp(zjmp, 1);
- }
|