]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/bzip2/bzip2.c
gzip, bzip2: add -n flag to suppress modification timestamp
[plan9front.git] / sys / src / cmd / bzip2 / bzip2.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "bzlib.h"
5
6 static  int     bzipf(char*, int, int);
7 static  int     bzip(char*, long, int, Biobuf*);
8
9 static  Biobuf  bout;
10 static  int     level;
11 static  int     debug;
12 static  int     verbose;
13
14
15 static void
16 usage(void)
17 {
18         fprint(2, "usage: bzip2 [-vcnD] [-1-9] [file ...]\n");
19         exits("usage");
20 }
21
22 void
23 main(int argc, char **argv)
24 {
25         int i, ok, stdout;
26         long mtime;
27
28         level = 6;
29         stdout = 0;
30         mtime = time(nil);
31         ARGBEGIN{
32         case 'D':
33                 debug++;
34                 break;
35         case 'v':
36                 verbose++;
37                 break;
38         case 'c':
39                 stdout++;
40                 break;
41         case 'n':
42                 mtime = 0;
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         if(argc == 0){
54                 Binit(&bout, 1, OWRITE);
55                 ok = bzip(nil, mtime, 0, &bout);
56                 Bterm(&bout);
57         }else{
58                 ok = 1;
59                 for(i = 0; i < argc; i++)
60                         ok &= bzipf(argv[i], !mtime, stdout);
61         }
62         exits(ok ? nil: "errors");
63 }
64
65 static int
66 bzipf(char *file, int nomtime, int stdout)
67 {
68         Dir *dir;
69         char ofile[128], *f, *s;
70         int ifd, ofd, ok;
71
72         ifd = open(file, OREAD);
73         if(ifd < 0){
74                 fprint(2, "bzip2: can't open %s: %r\n", file);
75                 return 0;
76         }
77         dir = dirfstat(ifd);
78         if(dir == nil){
79                 fprint(2, "bzip2: can't stat %s: %r\n", file);
80                 close(ifd);
81                 return 0;
82         }
83         if(dir->mode & DMDIR){
84                 fprint(2, "bzip2: can't compress a directory\n");
85                 close(ifd);
86                 free(dir);
87                 return 0;
88         }
89
90         if(stdout){
91                 ofd = 1;
92                 strcpy(ofile, "<stdout>");
93         }else{
94                 f = strrchr(file, '/');
95                 if(f != nil)
96                         f++;
97                 else
98                         f = file;
99                 s = strrchr(f, '.');
100                 if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
101                         *s = '\0';
102                         snprint(ofile, sizeof(ofile), "%s.tbz", f);
103                 }else
104                         snprint(ofile, sizeof(ofile), "%s.bz2", f);
105                 ofd = create(ofile, OWRITE, 0666);
106                 if(ofd < 0){
107                         fprint(2, "bzip2: can't open %s: %r\n", ofile);
108                         free(dir);
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 = bzip(file, nomtime ? 0 : dir->mtime, ifd, &bout);
119         if(!ok || Bflush(&bout) < 0){
120                 fprint(2, "bzip2: error writing %s: %r\n", ofile);
121                 if(!stdout)
122                         remove(ofile);
123         }
124         Bterm(&bout);
125         free(dir);
126         close(ifd);
127         close(ofd);
128         return ok;
129 }
130
131 static int
132 bzip(char *file, long mtime, int ifd, Biobuf *bout)
133 {
134         int e, n, done, onemore;
135         char buf[8192];
136         char obuf[8192];
137         Biobuf bin;
138         bz_stream strm;
139
140         USED(file);
141         USED(mtime);
142
143         memset(&strm, 0, sizeof strm);
144         BZ2_bzCompressInit(&strm, level, verbose, 0);
145
146         strm.next_in = buf;
147         strm.avail_in = 0;
148         strm.next_out = obuf;
149         strm.avail_out = sizeof obuf;
150
151         done = 0;
152         Binit(&bin, ifd, OREAD);
153
154         /*
155          * onemore is a crummy hack to go 'round the loop
156          * once after we finish, to flush the output buffer.
157          */
158         onemore = 1;
159         SET(e);
160         do {
161                 if(!done && strm.avail_in < sizeof buf) {
162                         if(strm.avail_in)
163                                 memmove(buf, strm.next_in, strm.avail_in);
164                         
165                         n = Bread(&bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
166                         if(n <= 0)
167                                 done = 1;
168                         else
169                                 strm.avail_in += n;
170                         strm.next_in = buf;
171                 }
172                 if(strm.avail_out < sizeof obuf) {
173                         Bwrite(bout, obuf, sizeof(obuf)-strm.avail_out);
174                         strm.next_out = obuf;
175                         strm.avail_out = sizeof obuf;
176                 }
177
178                 if(onemore == 0)
179                         break;
180         } while((e=BZ2_bzCompress(&strm, done ? BZ_FINISH : BZ_RUN)) == BZ_RUN_OK || e == BZ_FINISH_OK || onemore--);
181
182         if(e != BZ_STREAM_END) {
183                 fprint(2, "bzip2: compress failed\n");
184                 return 0;
185         }
186
187         if(BZ2_bzCompressEnd(&strm) != BZ_OK) {
188                 fprint(2, "bzip2: compress end failed (can't happen)\n");
189                 return 0;
190         }
191
192         Bterm(&bin);
193
194         return 1;
195 }