Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "bzlib.h"
6 static int bzipf(char*, int);
7 static int bzip(char*, long, int, Biobuf*);
9 static Biobuf bout;
10 static int level;
11 static int debug;
12 static int verbose;
15 static void
16 usage(void)
17 {
18 fprint(2, "usage: bzip2 [-vcD] [-1-9] [file ...]\n");
19 exits("usage");
20 }
22 void
23 main(int argc, char **argv)
24 {
25 int i, ok, stdout;
26 char **oargv;
28 oargv = argv;
29 level = 6;
30 stdout = 0;
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 'f':
42 /* force */
43 break;
44 case 'd':
45 /*
46 * gnu tar expects bzip2 -d to decompress
47 * humor it. ugh.
48 */
49 /* remove -d from command line - magic! */
50 if(strcmp(argv[0], "-d") == 0){
51 while(*argv++)
52 *(argv-1) = *argv;
53 }else
54 memmove(_args-1, _args, strlen(_args)+1);
55 exec("bunzip2", oargv);
56 sysfatal("exec bunzip2 failed");
57 break;
58 case '1': case '2': case '3': case '4':
59 case '5': case '6': case '7': case '8': case '9':
60 level = ARGC() - '0';
61 break;
62 default:
63 usage();
64 break;
65 }ARGEND
67 if(argc == 0){
68 Binit(&bout, 1, OWRITE);
69 ok = bzip(nil, time(0), 0, &bout);
70 Bterm(&bout);
71 }else{
72 ok = 1;
73 for(i = 0; i < argc; i++)
74 ok &= bzipf(argv[i], stdout);
75 }
76 exits(ok ? nil: "errors");
77 }
79 static int
80 bzipf(char *file, int stdout)
81 {
82 Dir *dir;
83 char ofile[128], *f, *s;
84 int ifd, ofd, ok;
86 ifd = open(file, OREAD);
87 if(ifd < 0){
88 fprint(2, "bzip2: can't open %s: %r\n", file);
89 return 0;
90 }
91 dir = dirfstat(ifd);
92 if(dir == nil){
93 fprint(2, "bzip2: can't stat %s: %r\n", file);
94 close(ifd);
95 return 0;
96 }
97 if(dir->mode & DMDIR){
98 fprint(2, "bzip2: can't compress a directory\n");
99 close(ifd);
100 free(dir);
101 return 0;
104 if(stdout){
105 ofd = 1;
106 strcpy(ofile, "<stdout>");
107 }else{
108 f = strrchr(file, '/');
109 if(f != nil)
110 f++;
111 else
112 f = file;
113 s = strrchr(f, '.');
114 if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
115 *s = '\0';
116 snprint(ofile, sizeof(ofile), "%s.tbz", f);
117 }else
118 snprint(ofile, sizeof(ofile), "%s.bz2", f);
119 ofd = create(ofile, OWRITE, 0666);
120 if(ofd < 0){
121 fprint(2, "bzip2: can't open %s: %r\n", ofile);
122 free(dir);
123 close(ifd);
124 return 0;
128 if(verbose)
129 fprint(2, "compressing %s to %s\n", file, ofile);
131 Binit(&bout, ofd, OWRITE);
132 ok = bzip(file, dir->mtime, ifd, &bout);
133 if(!ok || Bflush(&bout) < 0){
134 fprint(2, "bzip2: error writing %s: %r\n", ofile);
135 if(!stdout)
136 remove(ofile);
138 Bterm(&bout);
139 free(dir);
140 close(ifd);
141 close(ofd);
142 return ok;
145 static int
146 bzip(char *file, long mtime, int ifd, Biobuf *bout)
148 int e, n, done, onemore;
149 char buf[8192];
150 char obuf[8192];
151 Biobuf bin;
152 bz_stream strm;
154 USED(file);
155 USED(mtime);
157 memset(&strm, 0, sizeof strm);
158 BZ2_bzCompressInit(&strm, level, verbose, 0);
160 strm.next_in = buf;
161 strm.avail_in = 0;
162 strm.next_out = obuf;
163 strm.avail_out = sizeof obuf;
165 done = 0;
166 Binit(&bin, ifd, OREAD);
168 /*
169 * onemore is a crummy hack to go 'round the loop
170 * once after we finish, to flush the output buffer.
171 */
172 onemore = 1;
173 SET(e);
174 do {
175 if(!done && strm.avail_in < sizeof buf) {
176 if(strm.avail_in)
177 memmove(buf, strm.next_in, strm.avail_in);
179 n = Bread(&bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
180 if(n <= 0)
181 done = 1;
182 else
183 strm.avail_in += n;
184 strm.next_in = buf;
186 if(strm.avail_out < sizeof obuf) {
187 Bwrite(bout, obuf, sizeof(obuf)-strm.avail_out);
188 strm.next_out = obuf;
189 strm.avail_out = sizeof obuf;
192 if(onemore == 0)
193 break;
194 } while((e=BZ2_bzCompress(&strm, done ? BZ_FINISH : BZ_RUN)) == BZ_RUN_OK || e == BZ_FINISH_OK || onemore--);
196 if(e != BZ_STREAM_END) {
197 fprint(2, "bzip2: compress failed\n");
198 return 0;
201 if(BZ2_bzCompressEnd(&strm) != BZ_OK) {
202 fprint(2, "bzip2: compress end failed (can't happen)\n");
203 return 0;
206 Bterm(&bin);
208 return 1;