]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/gzip/gzip.c
2ba8c22c4b414ff0f899c4255e6a61be61789c64
[plan9front.git] / sys / src / cmd / gzip / gzip.c
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
22 usage(void)
23 {
24         fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n");
25         exits("usage");
26 }
27
28 void
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
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
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
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
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 }