xref: /plan9/sys/src/cmd/gzip/gzip.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
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