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