xref: /plan9/sys/src/cmd/gzip/gzip.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <flate.h>
5 #include "gzip.h"
6 
7 static	int	gzipf(char*, int);
8 static	int	gzip(char*, long, int, Biobuf*);
9 static	int	crcread(void *fd, void *buf, int n);
10 static	int	gzwrite(void *bout, void *buf, int n);
11 
12 static	Biobuf	bout;
13 static	ulong	crc;
14 static	ulong	*crctab;
15 static	int	debug;
16 static	int	eof;
17 static	int	level;
18 static	ulong	totr;
19 static	int	verbose;
20 
21 void
usage(void)22 usage(void)
23 {
24 	fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n");
25 	exits("usage");
26 }
27 
28 void
main(int argc,char * argv[])29 main(int argc, char *argv[])
30 {
31 	int i, ok, stdout;
32 
33 	level = 6;
34 	stdout = 0;
35 	ARGBEGIN{
36 	case 'D':
37 		debug++;
38 		break;
39 	case 'v':
40 		verbose++;
41 		break;
42 	case 'c':
43 		stdout = 1;
44 		break;
45 	case '1': case '2': case '3': case '4':
46 	case '5': case '6': case '7': case '8': case '9':
47 		level = ARGC() - '0';
48 		break;
49 	default:
50 		usage();
51 		break;
52 	}ARGEND
53 
54 	crctab = mkcrctab(GZCRCPOLY);
55 	ok = deflateinit();
56 	if(ok != FlateOk)
57 		sysfatal("deflateinit failed: %s", flateerr(ok));
58 
59 	if(argc == 0){
60 		Binit(&bout, 1, OWRITE);
61 		ok = gzip(nil, time(0), 0, &bout);
62 		Bterm(&bout);
63 	}else{
64 		ok = 1;
65 		for(i = 0; i < argc; i++)
66 			ok &= gzipf(argv[i], stdout);
67 	}
68 	exits(ok ? nil: "errors");
69 }
70 
71 static int
gzipf(char * file,int stdout)72 gzipf(char *file, int stdout)
73 {
74 	Dir *dir;
75 	char ofile[256], *f, *s;
76 	int ifd, ofd, ok;
77 
78 	ifd = open(file, OREAD);
79 	if(ifd < 0){
80 		fprint(2, "gzip: can't open %s: %r\n", file);
81 		return 0;
82 	}
83 	dir = dirfstat(ifd);
84 	if(dir == nil){
85 		fprint(2, "gzip: can't stat %s: %r\n", file);
86 		close(ifd);
87 		return 0;
88 	}
89 	if(dir->mode & DMDIR){
90 		fprint(2, "gzip: can't compress a directory\n");
91 		close(ifd);
92 		free(dir);
93 		return 0;
94 	}
95 
96 	if(stdout){
97 		ofd = 1;
98 		strcpy(ofile, "<stdout>");
99 	}else{
100 		f = strrchr(file, '/');
101 		if(f != nil)
102 			f++;
103 		else
104 			f = file;
105 		s = strrchr(f, '.');
106 		if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
107 			*s = '\0';
108 			snprint(ofile, sizeof(ofile), "%s.tgz", f);
109 		}else
110 			snprint(ofile, sizeof(ofile), "%s.gz", f);
111 		ofd = create(ofile, OWRITE, 0666);
112 		if(ofd < 0){
113 			fprint(2, "gzip: can't open %s: %r\n", ofile);
114 			close(ifd);
115 			return 0;
116 		}
117 	}
118 
119 	if(verbose)
120 		fprint(2, "compressing %s to %s\n", file, ofile);
121 
122 	Binit(&bout, ofd, OWRITE);
123 	ok = gzip(file, dir->mtime, ifd, &bout);
124 	if(!ok || Bflush(&bout) < 0){
125 		fprint(2, "gzip: error writing %s: %r\n", ofile);
126 		if(!stdout)
127 			remove(ofile);
128 	}
129 	Bterm(&bout);
130 	free(dir);
131 	close(ifd);
132 	close(ofd);
133 	return ok;
134 }
135 
136 static int
gzip(char * file,long mtime,int ifd,Biobuf * bout)137 gzip(char *file, long mtime, int ifd, Biobuf *bout)
138 {
139 	int flags, err;
140 
141 	flags = 0;
142 	Bputc(bout, GZMAGIC1);
143 	Bputc(bout, GZMAGIC2);
144 	Bputc(bout, GZDEFLATE);
145 
146 	if(file != nil)
147 		flags |= GZFNAME;
148 	Bputc(bout, flags);
149 
150 	Bputc(bout, mtime);
151 	Bputc(bout, mtime>>8);
152 	Bputc(bout, mtime>>16);
153 	Bputc(bout, mtime>>24);
154 
155 	Bputc(bout, 0);
156 	Bputc(bout, GZOSINFERNO);
157 
158 	if(flags & GZFNAME)
159 		Bwrite(bout, file, strlen(file)+1);
160 
161 	crc = 0;
162 	eof = 0;
163 	totr = 0;
164 	err = deflate(bout, gzwrite, (void*)ifd, crcread, level, debug);
165 	if(err != FlateOk){
166 		fprint(2, "gzip: deflate failed: %s\n", flateerr(err));
167 		return 0;
168 	}
169 
170 	Bputc(bout, crc);
171 	Bputc(bout, crc>>8);
172 	Bputc(bout, crc>>16);
173 	Bputc(bout, crc>>24);
174 
175 	Bputc(bout, totr);
176 	Bputc(bout, totr>>8);
177 	Bputc(bout, totr>>16);
178 	Bputc(bout, totr>>24);
179 
180 	return 1;
181 }
182 
183 static int
crcread(void * fd,void * buf,int n)184 crcread(void *fd, void *buf, int n)
185 {
186 	int nr, m;
187 
188 	nr = 0;
189 	for(; !eof && n > 0; n -= m){
190 		m = read((int)(uintptr)fd, (char*)buf+nr, n);
191 		if(m <= 0){
192 			eof = 1;
193 			if(m < 0)
194 				return -1;
195 			break;
196 		}
197 		nr += m;
198 	}
199 	crc = blockcrc(crctab, crc, buf, nr);
200 	totr += nr;
201 	return nr;
202 }
203 
204 static int
gzwrite(void * bout,void * buf,int n)205 gzwrite(void *bout, void *buf, int n)
206 {
207 	if(n != Bwrite(bout, buf, n)){
208 		eof = 1;
209 		return -1;
210 	}
211 	return n;
212 }
213