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 "gzip.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier static int gzipf(char*, int);
87dd7cddfSDavid du Colombier static int gzip(char*, long, int, Biobuf*);
97dd7cddfSDavid du Colombier static int crcread(void *fd, void *buf, int n);
107dd7cddfSDavid du Colombier static int gzwrite(void *bout, void *buf, int n);
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier static Biobuf bout;
137dd7cddfSDavid du Colombier static ulong crc;
1480ee5cbfSDavid du Colombier static ulong *crctab;
157dd7cddfSDavid du Colombier static int debug;
167dd7cddfSDavid du Colombier static int eof;
177dd7cddfSDavid du Colombier static int level;
187dd7cddfSDavid du Colombier static ulong totr;
197dd7cddfSDavid du Colombier static int verbose;
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier void
usage(void)227dd7cddfSDavid du Colombier usage(void)
237dd7cddfSDavid du Colombier {
247dd7cddfSDavid du Colombier fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n");
257dd7cddfSDavid du Colombier exits("usage");
267dd7cddfSDavid du Colombier }
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier void
main(int argc,char * argv[])297dd7cddfSDavid du Colombier main(int argc, char *argv[])
307dd7cddfSDavid du Colombier {
317dd7cddfSDavid du Colombier int i, ok, stdout;
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier level = 6;
347dd7cddfSDavid du Colombier stdout = 0;
357dd7cddfSDavid du Colombier ARGBEGIN{
367dd7cddfSDavid du Colombier case 'D':
377dd7cddfSDavid du Colombier debug++;
387dd7cddfSDavid du Colombier break;
397dd7cddfSDavid du Colombier case 'v':
407dd7cddfSDavid du Colombier verbose++;
417dd7cddfSDavid du Colombier break;
427dd7cddfSDavid du Colombier case 'c':
437dd7cddfSDavid du Colombier stdout = 1;
447dd7cddfSDavid du Colombier break;
457dd7cddfSDavid du Colombier case '1': case '2': case '3': case '4':
467dd7cddfSDavid du Colombier case '5': case '6': case '7': case '8': case '9':
477dd7cddfSDavid du Colombier level = ARGC() - '0';
487dd7cddfSDavid du Colombier break;
497dd7cddfSDavid du Colombier default:
507dd7cddfSDavid du Colombier usage();
517dd7cddfSDavid du Colombier break;
527dd7cddfSDavid du Colombier }ARGEND
537dd7cddfSDavid du Colombier
5480ee5cbfSDavid du Colombier crctab = mkcrctab(GZCRCPOLY);
5580ee5cbfSDavid du Colombier ok = deflateinit();
5680ee5cbfSDavid du Colombier if(ok != FlateOk)
57*14cc0f53SDavid du Colombier sysfatal("deflateinit failed: %s", flateerr(ok));
587dd7cddfSDavid du Colombier
597dd7cddfSDavid du Colombier if(argc == 0){
607dd7cddfSDavid du Colombier Binit(&bout, 1, OWRITE);
617dd7cddfSDavid du Colombier ok = gzip(nil, time(0), 0, &bout);
627dd7cddfSDavid du Colombier Bterm(&bout);
637dd7cddfSDavid du Colombier }else{
647dd7cddfSDavid du Colombier ok = 1;
657dd7cddfSDavid du Colombier for(i = 0; i < argc; i++)
667dd7cddfSDavid du Colombier ok &= gzipf(argv[i], stdout);
677dd7cddfSDavid du Colombier }
687dd7cddfSDavid du Colombier exits(ok ? nil: "errors");
697dd7cddfSDavid du Colombier }
707dd7cddfSDavid du Colombier
717dd7cddfSDavid du Colombier static int
gzipf(char * file,int stdout)727dd7cddfSDavid du Colombier gzipf(char *file, int stdout)
737dd7cddfSDavid du Colombier {
749a747e4fSDavid du Colombier Dir *dir;
759a747e4fSDavid du Colombier char ofile[256], *f, *s;
767dd7cddfSDavid du Colombier int ifd, ofd, ok;
777dd7cddfSDavid du Colombier
787dd7cddfSDavid du Colombier ifd = open(file, OREAD);
797dd7cddfSDavid du Colombier if(ifd < 0){
807dd7cddfSDavid du Colombier fprint(2, "gzip: can't open %s: %r\n", file);
817dd7cddfSDavid du Colombier return 0;
827dd7cddfSDavid du Colombier }
839a747e4fSDavid du Colombier dir = dirfstat(ifd);
849a747e4fSDavid du Colombier if(dir == nil){
857dd7cddfSDavid du Colombier fprint(2, "gzip: can't stat %s: %r\n", file);
867dd7cddfSDavid du Colombier close(ifd);
877dd7cddfSDavid du Colombier return 0;
887dd7cddfSDavid du Colombier }
899a747e4fSDavid du Colombier if(dir->mode & DMDIR){
907dd7cddfSDavid du Colombier fprint(2, "gzip: can't compress a directory\n");
917dd7cddfSDavid du Colombier close(ifd);
929a747e4fSDavid du Colombier free(dir);
937dd7cddfSDavid du Colombier return 0;
947dd7cddfSDavid du Colombier }
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier if(stdout){
977dd7cddfSDavid du Colombier ofd = 1;
987dd7cddfSDavid du Colombier strcpy(ofile, "<stdout>");
997dd7cddfSDavid du Colombier }else{
1007dd7cddfSDavid du Colombier f = strrchr(file, '/');
1017dd7cddfSDavid du Colombier if(f != nil)
1027dd7cddfSDavid du Colombier f++;
1037dd7cddfSDavid du Colombier else
1047dd7cddfSDavid du Colombier f = file;
1057dd7cddfSDavid du Colombier s = strrchr(f, '.');
1067dd7cddfSDavid du Colombier if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
1077dd7cddfSDavid du Colombier *s = '\0';
1087dd7cddfSDavid du Colombier snprint(ofile, sizeof(ofile), "%s.tgz", f);
1097dd7cddfSDavid du Colombier }else
1107dd7cddfSDavid du Colombier snprint(ofile, sizeof(ofile), "%s.gz", f);
1117dd7cddfSDavid du Colombier ofd = create(ofile, OWRITE, 0666);
1127dd7cddfSDavid du Colombier if(ofd < 0){
1137dd7cddfSDavid du Colombier fprint(2, "gzip: can't open %s: %r\n", ofile);
1147dd7cddfSDavid du Colombier close(ifd);
1157dd7cddfSDavid du Colombier return 0;
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier if(verbose)
1207dd7cddfSDavid du Colombier fprint(2, "compressing %s to %s\n", file, ofile);
1217dd7cddfSDavid du Colombier
1227dd7cddfSDavid du Colombier Binit(&bout, ofd, OWRITE);
1239a747e4fSDavid du Colombier ok = gzip(file, dir->mtime, ifd, &bout);
1247dd7cddfSDavid du Colombier if(!ok || Bflush(&bout) < 0){
1257dd7cddfSDavid du Colombier fprint(2, "gzip: error writing %s: %r\n", ofile);
1267dd7cddfSDavid du Colombier if(!stdout)
1277dd7cddfSDavid du Colombier remove(ofile);
1287dd7cddfSDavid du Colombier }
1297dd7cddfSDavid du Colombier Bterm(&bout);
1309a747e4fSDavid du Colombier free(dir);
1317dd7cddfSDavid du Colombier close(ifd);
1327dd7cddfSDavid du Colombier close(ofd);
1337dd7cddfSDavid du Colombier return ok;
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier static int
gzip(char * file,long mtime,int ifd,Biobuf * bout)1377dd7cddfSDavid du Colombier gzip(char *file, long mtime, int ifd, Biobuf *bout)
1387dd7cddfSDavid du Colombier {
13980ee5cbfSDavid du Colombier int flags, err;
1407dd7cddfSDavid du Colombier
1417dd7cddfSDavid du Colombier flags = 0;
1427dd7cddfSDavid du Colombier Bputc(bout, GZMAGIC1);
1437dd7cddfSDavid du Colombier Bputc(bout, GZMAGIC2);
1447dd7cddfSDavid du Colombier Bputc(bout, GZDEFLATE);
1457dd7cddfSDavid du Colombier
1467dd7cddfSDavid du Colombier if(file != nil)
1477dd7cddfSDavid du Colombier flags |= GZFNAME;
1487dd7cddfSDavid du Colombier Bputc(bout, flags);
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier Bputc(bout, mtime);
1517dd7cddfSDavid du Colombier Bputc(bout, mtime>>8);
1527dd7cddfSDavid du Colombier Bputc(bout, mtime>>16);
1537dd7cddfSDavid du Colombier Bputc(bout, mtime>>24);
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier Bputc(bout, 0);
1567dd7cddfSDavid du Colombier Bputc(bout, GZOSINFERNO);
1577dd7cddfSDavid du Colombier
1587dd7cddfSDavid du Colombier if(flags & GZFNAME)
1597dd7cddfSDavid du Colombier Bwrite(bout, file, strlen(file)+1);
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier crc = 0;
1627dd7cddfSDavid du Colombier eof = 0;
1637dd7cddfSDavid du Colombier totr = 0;
16480ee5cbfSDavid du Colombier err = deflate(bout, gzwrite, (void*)ifd, crcread, level, debug);
16580ee5cbfSDavid du Colombier if(err != FlateOk){
16680ee5cbfSDavid du Colombier fprint(2, "gzip: deflate failed: %s\n", flateerr(err));
1677dd7cddfSDavid du Colombier return 0;
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier
1707dd7cddfSDavid du Colombier Bputc(bout, crc);
1717dd7cddfSDavid du Colombier Bputc(bout, crc>>8);
1727dd7cddfSDavid du Colombier Bputc(bout, crc>>16);
1737dd7cddfSDavid du Colombier Bputc(bout, crc>>24);
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier Bputc(bout, totr);
1767dd7cddfSDavid du Colombier Bputc(bout, totr>>8);
1777dd7cddfSDavid du Colombier Bputc(bout, totr>>16);
1787dd7cddfSDavid du Colombier Bputc(bout, totr>>24);
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier return 1;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier static int
crcread(void * fd,void * buf,int n)1847dd7cddfSDavid du Colombier crcread(void *fd, void *buf, int n)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier int nr, m;
1877dd7cddfSDavid du Colombier
1887dd7cddfSDavid du Colombier nr = 0;
1897dd7cddfSDavid du Colombier for(; !eof && n > 0; n -= m){
19074f16c81SDavid du Colombier m = read((int)(uintptr)fd, (char*)buf+nr, n);
1917dd7cddfSDavid du Colombier if(m <= 0){
1927dd7cddfSDavid du Colombier eof = 1;
19380ee5cbfSDavid du Colombier if(m < 0)
19480ee5cbfSDavid du Colombier return -1;
1957dd7cddfSDavid du Colombier break;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier nr += m;
1987dd7cddfSDavid du Colombier }
19980ee5cbfSDavid du Colombier crc = blockcrc(crctab, crc, buf, nr);
2007dd7cddfSDavid du Colombier totr += nr;
2017dd7cddfSDavid du Colombier return nr;
2027dd7cddfSDavid du Colombier }
2037dd7cddfSDavid du Colombier
2047dd7cddfSDavid du Colombier static int
gzwrite(void * bout,void * buf,int n)2057dd7cddfSDavid du Colombier gzwrite(void *bout, void *buf, int n)
2067dd7cddfSDavid du Colombier {
2077dd7cddfSDavid du Colombier if(n != Bwrite(bout, buf, n)){
2087dd7cddfSDavid du Colombier eof = 1;
2097dd7cddfSDavid du Colombier return -1;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier return n;
2127dd7cddfSDavid du Colombier }
213