xref: /plan9/sys/src/cmd/bzip2/bzip2.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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
usage(void)16 usage(void)
17 {
18 	fprint(2, "usage: bzip2 [-vcD] [-1-9] [file ...]\n");
19 	exits("usage");
20 }
21 
22 void
main(int argc,char ** argv)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
bzipf(char * file,int stdout)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
bzip(char * file,long mtime,int ifd,Biobuf * bout)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 }
191