159cc4ca5SDavid du Colombier #include <u.h>
259cc4ca5SDavid du Colombier #include <libc.h>
359cc4ca5SDavid du Colombier #include <bio.h>
459cc4ca5SDavid du Colombier #include "bzlib.h"
559cc4ca5SDavid du Colombier
659cc4ca5SDavid du Colombier static int bzipf(char*, int);
759cc4ca5SDavid du Colombier static int bzip(char*, long, int, Biobuf*);
859cc4ca5SDavid du Colombier
959cc4ca5SDavid du Colombier static Biobuf bout;
1059cc4ca5SDavid du Colombier static int level;
1159cc4ca5SDavid du Colombier static int debug;
1259cc4ca5SDavid du Colombier static int verbose;
1359cc4ca5SDavid du Colombier
1459cc4ca5SDavid du Colombier
1559cc4ca5SDavid du Colombier static void
usage(void)1659cc4ca5SDavid du Colombier usage(void)
1759cc4ca5SDavid du Colombier {
1859cc4ca5SDavid du Colombier fprint(2, "usage: bzip2 [-vcD] [-1-9] [file ...]\n");
1959cc4ca5SDavid du Colombier exits("usage");
2059cc4ca5SDavid du Colombier }
2159cc4ca5SDavid du Colombier
2259cc4ca5SDavid du Colombier void
main(int argc,char ** argv)2359cc4ca5SDavid du Colombier main(int argc, char **argv)
2459cc4ca5SDavid du Colombier {
2559cc4ca5SDavid du Colombier int i, ok, stdout;
2659cc4ca5SDavid du Colombier
2759cc4ca5SDavid du Colombier level = 6;
2859cc4ca5SDavid du Colombier stdout = 0;
2959cc4ca5SDavid du Colombier ARGBEGIN{
3059cc4ca5SDavid du Colombier case 'D':
3159cc4ca5SDavid du Colombier debug++;
3259cc4ca5SDavid du Colombier break;
3359cc4ca5SDavid du Colombier case 'v':
3459cc4ca5SDavid du Colombier verbose++;
3559cc4ca5SDavid du Colombier break;
3659cc4ca5SDavid du Colombier case 'c':
3759cc4ca5SDavid du Colombier stdout++;
3859cc4ca5SDavid du Colombier break;
3959cc4ca5SDavid du Colombier case '1': case '2': case '3': case '4':
4059cc4ca5SDavid du Colombier case '5': case '6': case '7': case '8': case '9':
4159cc4ca5SDavid du Colombier level = ARGC() - '0';
4259cc4ca5SDavid du Colombier break;
4359cc4ca5SDavid du Colombier default:
4459cc4ca5SDavid du Colombier usage();
4559cc4ca5SDavid du Colombier break;
4659cc4ca5SDavid du Colombier }ARGEND
4759cc4ca5SDavid du Colombier
4859cc4ca5SDavid du Colombier if(argc == 0){
4959cc4ca5SDavid du Colombier Binit(&bout, 1, OWRITE);
5059cc4ca5SDavid du Colombier ok = bzip(nil, time(0), 0, &bout);
5159cc4ca5SDavid du Colombier Bterm(&bout);
5259cc4ca5SDavid du Colombier }else{
5359cc4ca5SDavid du Colombier ok = 1;
5459cc4ca5SDavid du Colombier for(i = 0; i < argc; i++)
5559cc4ca5SDavid du Colombier ok &= bzipf(argv[i], stdout);
5659cc4ca5SDavid du Colombier }
5759cc4ca5SDavid du Colombier exits(ok ? nil: "errors");
5859cc4ca5SDavid du Colombier }
5959cc4ca5SDavid du Colombier
6059cc4ca5SDavid du Colombier static int
bzipf(char * file,int stdout)6159cc4ca5SDavid du Colombier bzipf(char *file, int stdout)
6259cc4ca5SDavid du Colombier {
63*9a747e4fSDavid du Colombier Dir *dir;
64*9a747e4fSDavid du Colombier char ofile[128], *f, *s;
6559cc4ca5SDavid du Colombier int ifd, ofd, ok;
6659cc4ca5SDavid du Colombier
6759cc4ca5SDavid du Colombier ifd = open(file, OREAD);
6859cc4ca5SDavid du Colombier if(ifd < 0){
6959cc4ca5SDavid du Colombier fprint(2, "bzip2: can't open %s: %r\n", file);
7059cc4ca5SDavid du Colombier return 0;
7159cc4ca5SDavid du Colombier }
72*9a747e4fSDavid du Colombier dir = dirfstat(ifd);
73*9a747e4fSDavid du Colombier if(dir == nil){
7459cc4ca5SDavid du Colombier fprint(2, "bzip2: can't stat %s: %r\n", file);
7559cc4ca5SDavid du Colombier close(ifd);
7659cc4ca5SDavid du Colombier return 0;
7759cc4ca5SDavid du Colombier }
78*9a747e4fSDavid du Colombier if(dir->mode & DMDIR){
7959cc4ca5SDavid du Colombier fprint(2, "bzip2: can't compress a directory\n");
8059cc4ca5SDavid du Colombier close(ifd);
81*9a747e4fSDavid du Colombier free(dir);
8259cc4ca5SDavid du Colombier return 0;
8359cc4ca5SDavid du Colombier }
8459cc4ca5SDavid du Colombier
8559cc4ca5SDavid du Colombier if(stdout){
8659cc4ca5SDavid du Colombier ofd = 1;
8759cc4ca5SDavid du Colombier strcpy(ofile, "<stdout>");
8859cc4ca5SDavid du Colombier }else{
8959cc4ca5SDavid du Colombier f = strrchr(file, '/');
9059cc4ca5SDavid du Colombier if(f != nil)
9159cc4ca5SDavid du Colombier f++;
9259cc4ca5SDavid du Colombier else
9359cc4ca5SDavid du Colombier f = file;
9459cc4ca5SDavid du Colombier s = strrchr(f, '.');
9559cc4ca5SDavid du Colombier if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
9659cc4ca5SDavid du Colombier *s = '\0';
9759cc4ca5SDavid du Colombier snprint(ofile, sizeof(ofile), "%s.tbz", f);
9859cc4ca5SDavid du Colombier }else
9959cc4ca5SDavid du Colombier snprint(ofile, sizeof(ofile), "%s.bz2", f);
10059cc4ca5SDavid du Colombier ofd = create(ofile, OWRITE, 0666);
10159cc4ca5SDavid du Colombier if(ofd < 0){
10259cc4ca5SDavid du Colombier fprint(2, "bzip2: can't open %s: %r\n", ofile);
103*9a747e4fSDavid du Colombier free(dir);
10459cc4ca5SDavid du Colombier close(ifd);
10559cc4ca5SDavid du Colombier return 0;
10659cc4ca5SDavid du Colombier }
10759cc4ca5SDavid du Colombier }
10859cc4ca5SDavid du Colombier
10959cc4ca5SDavid du Colombier if(verbose)
11059cc4ca5SDavid du Colombier fprint(2, "compressing %s to %s\n", file, ofile);
11159cc4ca5SDavid du Colombier
11259cc4ca5SDavid du Colombier Binit(&bout, ofd, OWRITE);
113*9a747e4fSDavid du Colombier ok = bzip(file, dir->mtime, ifd, &bout);
11459cc4ca5SDavid du Colombier if(!ok || Bflush(&bout) < 0){
11559cc4ca5SDavid du Colombier fprint(2, "bzip2: error writing %s: %r\n", ofile);
11659cc4ca5SDavid du Colombier if(!stdout)
11759cc4ca5SDavid du Colombier remove(ofile);
11859cc4ca5SDavid du Colombier }
11959cc4ca5SDavid du Colombier Bterm(&bout);
120*9a747e4fSDavid du Colombier free(dir);
12159cc4ca5SDavid du Colombier close(ifd);
12259cc4ca5SDavid du Colombier close(ofd);
12359cc4ca5SDavid du Colombier return ok;
12459cc4ca5SDavid du Colombier }
12559cc4ca5SDavid du Colombier
12659cc4ca5SDavid du Colombier static int
bzip(char * file,long mtime,int ifd,Biobuf * bout)12759cc4ca5SDavid du Colombier bzip(char *file, long mtime, int ifd, Biobuf *bout)
12859cc4ca5SDavid du Colombier {
12959cc4ca5SDavid du Colombier int e, n, done, onemore;
13059cc4ca5SDavid du Colombier char buf[8192];
13159cc4ca5SDavid du Colombier char obuf[8192];
13259cc4ca5SDavid du Colombier Biobuf bin;
13359cc4ca5SDavid du Colombier bz_stream strm;
13459cc4ca5SDavid du Colombier
13559cc4ca5SDavid du Colombier USED(file);
13659cc4ca5SDavid du Colombier USED(mtime);
13759cc4ca5SDavid du Colombier
13859cc4ca5SDavid du Colombier memset(&strm, 0, sizeof strm);
13959cc4ca5SDavid du Colombier BZ2_bzCompressInit(&strm, level, verbose, 0);
14059cc4ca5SDavid du Colombier
14159cc4ca5SDavid du Colombier strm.next_in = buf;
14259cc4ca5SDavid du Colombier strm.avail_in = 0;
14359cc4ca5SDavid du Colombier strm.next_out = obuf;
14459cc4ca5SDavid du Colombier strm.avail_out = sizeof obuf;
14559cc4ca5SDavid du Colombier
14659cc4ca5SDavid du Colombier done = 0;
14759cc4ca5SDavid du Colombier Binit(&bin, ifd, OREAD);
14859cc4ca5SDavid du Colombier
14959cc4ca5SDavid du Colombier /*
15059cc4ca5SDavid du Colombier * onemore is a crummy hack to go 'round the loop
15159cc4ca5SDavid du Colombier * once after we finish, to flush the output buffer.
15259cc4ca5SDavid du Colombier */
15359cc4ca5SDavid du Colombier onemore = 1;
15459cc4ca5SDavid du Colombier SET(e);
15559cc4ca5SDavid du Colombier do {
15659cc4ca5SDavid du Colombier if(!done && strm.avail_in < sizeof buf) {
15759cc4ca5SDavid du Colombier if(strm.avail_in)
15859cc4ca5SDavid du Colombier memmove(buf, strm.next_in, strm.avail_in);
15959cc4ca5SDavid du Colombier
16059cc4ca5SDavid du Colombier n = Bread(&bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
16159cc4ca5SDavid du Colombier if(n <= 0)
16259cc4ca5SDavid du Colombier done = 1;
16359cc4ca5SDavid du Colombier else
16459cc4ca5SDavid du Colombier strm.avail_in += n;
16559cc4ca5SDavid du Colombier strm.next_in = buf;
16659cc4ca5SDavid du Colombier }
16759cc4ca5SDavid du Colombier if(strm.avail_out < sizeof obuf) {
16859cc4ca5SDavid du Colombier Bwrite(bout, obuf, sizeof(obuf)-strm.avail_out);
16959cc4ca5SDavid du Colombier strm.next_out = obuf;
17059cc4ca5SDavid du Colombier strm.avail_out = sizeof obuf;
17159cc4ca5SDavid du Colombier }
17259cc4ca5SDavid du Colombier
17359cc4ca5SDavid du Colombier if(onemore == 0)
17459cc4ca5SDavid du Colombier break;
17559cc4ca5SDavid du Colombier } while((e=BZ2_bzCompress(&strm, done ? BZ_FINISH : BZ_RUN)) == BZ_RUN_OK || e == BZ_FINISH_OK || onemore--);
17659cc4ca5SDavid du Colombier
17759cc4ca5SDavid du Colombier if(e != BZ_STREAM_END) {
17859cc4ca5SDavid du Colombier fprint(2, "bzip2: compress failed\n");
17959cc4ca5SDavid du Colombier return 0;
18059cc4ca5SDavid du Colombier }
18159cc4ca5SDavid du Colombier
18259cc4ca5SDavid du Colombier if(BZ2_bzCompressEnd(&strm) != BZ_OK) {
18359cc4ca5SDavid du Colombier fprint(2, "bzip2: compress end failed (can't happen)\n");
18459cc4ca5SDavid du Colombier return 0;
18559cc4ca5SDavid du Colombier }
18659cc4ca5SDavid du Colombier
187*9a747e4fSDavid du Colombier Bterm(&bin);
188*9a747e4fSDavid du Colombier
18959cc4ca5SDavid du Colombier return 1;
19059cc4ca5SDavid du Colombier }
191