Blob


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