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