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