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