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;
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
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 }
60 static int
61 bzipf(char *file, int stdout)
62 {
63 Dir *dir;
64 char ofile[128], *f, *s;
65 int ifd, ofd, ok;
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 }
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;
109 if(verbose)
110 fprint(2, "compressing %s to %s\n", file, ofile);
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);
119 Bterm(&bout);
120 free(dir);
121 close(ifd);
122 close(ofd);
123 return ok;
126 static int
127 bzip(char *file, long mtime, int ifd, Biobuf *bout)
129 int e, n, done, onemore;
130 char buf[8192];
131 char obuf[8192];
132 Biobuf bin;
133 bz_stream strm;
135 USED(file);
136 USED(mtime);
138 memset(&strm, 0, sizeof strm);
139 BZ2_bzCompressInit(&strm, level, verbose, 0);
141 strm.next_in = buf;
142 strm.avail_in = 0;
143 strm.next_out = obuf;
144 strm.avail_out = sizeof obuf;
146 done = 0;
147 Binit(&bin, ifd, OREAD);
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);
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;
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;
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--);
177 if(e != BZ_STREAM_END) {
178 fprint(2, "bzip2: compress failed\n");
179 return 0;
182 if(BZ2_bzCompressEnd(&strm) != BZ_OK) {
183 fprint(2, "bzip2: compress end failed (can't happen)\n");
184 return 0;
187 Bterm(&bin);
189 return 1;