|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <bio.h> | 
|  | #include "bzlib.h" | 
|  |  | 
|  | static	int	bzipf(char*, int); | 
|  | static	int	bzip(char*, long, int, Biobuf*); | 
|  |  | 
|  | static	Biobuf	bout; | 
|  | static	int	level; | 
|  | static	int	debug; | 
|  | static	int	verbose; | 
|  |  | 
|  |  | 
|  | static void | 
|  | usage(void) | 
|  | { | 
|  | fprint(2, "usage: bzip2 [-vcD] [-1-9] [file ...]\n"); | 
|  | exits("usage"); | 
|  | } | 
|  |  | 
|  | void | 
|  | main(int argc, char **argv) | 
|  | { | 
|  | int i, ok, stdout; | 
|  | char **oargv; | 
|  |  | 
|  | oargv = argv; | 
|  | level = 6; | 
|  | stdout = 0; | 
|  | ARGBEGIN{ | 
|  | case 'D': | 
|  | debug++; | 
|  | break; | 
|  | case 'v': | 
|  | verbose++; | 
|  | break; | 
|  | case 'c': | 
|  | stdout++; | 
|  | break; | 
|  | case 'f': | 
|  | /* force */ | 
|  | break; | 
|  | case 'd': | 
|  | /* | 
|  | * gnu tar expects bzip2 -d to decompress | 
|  | * humor it.  ugh. | 
|  | */ | 
|  | /* remove -d from command line - magic! */ | 
|  | if(strcmp(argv[0], "-d") == 0){ | 
|  | while(*argv++) | 
|  | *(argv-1) = *argv; | 
|  | }else | 
|  | memmove(_args-1, _args, strlen(_args)+1); | 
|  | exec("bunzip2", oargv); | 
|  | sysfatal("exec bunzip2 failed"); | 
|  | break; | 
|  | case '1': case '2': case '3': case '4': | 
|  | case '5': case '6': case '7': case '8': case '9': | 
|  | level = ARGC() - '0'; | 
|  | break; | 
|  | default: | 
|  | usage(); | 
|  | break; | 
|  | }ARGEND | 
|  |  | 
|  | if(argc == 0){ | 
|  | Binit(&bout, 1, OWRITE); | 
|  | ok = bzip(nil, time(0), 0, &bout); | 
|  | Bterm(&bout); | 
|  | }else{ | 
|  | ok = 1; | 
|  | for(i = 0; i < argc; i++) | 
|  | ok &= bzipf(argv[i], stdout); | 
|  | } | 
|  | exits(ok ? nil: "errors"); | 
|  | } | 
|  |  | 
|  | static int | 
|  | bzipf(char *file, int stdout) | 
|  | { | 
|  | Dir *dir; | 
|  | char ofile[128], *f, *s; | 
|  | int ifd, ofd, ok; | 
|  |  | 
|  | ifd = open(file, OREAD); | 
|  | if(ifd < 0){ | 
|  | fprint(2, "bzip2: can't open %s: %r\n", file); | 
|  | return 0; | 
|  | } | 
|  | dir = dirfstat(ifd); | 
|  | if(dir == nil){ | 
|  | fprint(2, "bzip2: can't stat %s: %r\n", file); | 
|  | close(ifd); | 
|  | return 0; | 
|  | } | 
|  | if(dir->mode & DMDIR){ | 
|  | fprint(2, "bzip2: can't compress a directory\n"); | 
|  | close(ifd); | 
|  | free(dir); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(stdout){ | 
|  | ofd = 1; | 
|  | strcpy(ofile, "<stdout>"); | 
|  | }else{ | 
|  | f = strrchr(file, '/'); | 
|  | if(f != nil) | 
|  | f++; | 
|  | else | 
|  | f = file; | 
|  | s = strrchr(f, '.'); | 
|  | if(s != nil && s != ofile && strcmp(s, ".tar") == 0){ | 
|  | *s = '\0'; | 
|  | snprint(ofile, sizeof(ofile), "%s.tbz", f); | 
|  | }else | 
|  | snprint(ofile, sizeof(ofile), "%s.bz2", f); | 
|  | ofd = create(ofile, OWRITE, 0666); | 
|  | if(ofd < 0){ | 
|  | fprint(2, "bzip2: can't open %s: %r\n", ofile); | 
|  | free(dir); | 
|  | close(ifd); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(verbose) | 
|  | fprint(2, "compressing %s to %s\n", file, ofile); | 
|  |  | 
|  | Binit(&bout, ofd, OWRITE); | 
|  | ok = bzip(file, dir->mtime, ifd, &bout); | 
|  | if(!ok || Bflush(&bout) < 0){ | 
|  | fprint(2, "bzip2: error writing %s: %r\n", ofile); | 
|  | if(!stdout) | 
|  | remove(ofile); | 
|  | } | 
|  | Bterm(&bout); | 
|  | free(dir); | 
|  | close(ifd); | 
|  | close(ofd); | 
|  | return ok; | 
|  | } | 
|  |  | 
|  | static int | 
|  | bzip(char *file, long mtime, int ifd, Biobuf *bout) | 
|  | { | 
|  | int e, n, done, onemore; | 
|  | char buf[8192]; | 
|  | char obuf[8192]; | 
|  | Biobuf bin; | 
|  | bz_stream strm; | 
|  |  | 
|  | USED(file); | 
|  | USED(mtime); | 
|  |  | 
|  | memset(&strm, 0, sizeof strm); | 
|  | BZ2_bzCompressInit(&strm, level, verbose, 0); | 
|  |  | 
|  | strm.next_in = buf; | 
|  | strm.avail_in = 0; | 
|  | strm.next_out = obuf; | 
|  | strm.avail_out = sizeof obuf; | 
|  |  | 
|  | done = 0; | 
|  | Binit(&bin, ifd, OREAD); | 
|  |  | 
|  | /* | 
|  | * onemore is a crummy hack to go 'round the loop | 
|  | * once after we finish, to flush the output buffer. | 
|  | */ | 
|  | onemore = 1; | 
|  | SET(e); | 
|  | do { | 
|  | if(!done && strm.avail_in < sizeof buf) { | 
|  | if(strm.avail_in) | 
|  | memmove(buf, strm.next_in, strm.avail_in); | 
|  |  | 
|  | n = Bread(&bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in); | 
|  | if(n <= 0) | 
|  | done = 1; | 
|  | else | 
|  | strm.avail_in += n; | 
|  | strm.next_in = buf; | 
|  | } | 
|  | if(strm.avail_out < sizeof obuf) { | 
|  | Bwrite(bout, obuf, sizeof(obuf)-strm.avail_out); | 
|  | strm.next_out = obuf; | 
|  | strm.avail_out = sizeof obuf; | 
|  | } | 
|  |  | 
|  | if(onemore == 0) | 
|  | break; | 
|  | } while((e=BZ2_bzCompress(&strm, done ? BZ_FINISH : BZ_RUN)) == BZ_RUN_OK || e == BZ_FINISH_OK || onemore--); | 
|  |  | 
|  | if(e != BZ_STREAM_END) { | 
|  | fprint(2, "bzip2: compress failed\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(BZ2_bzCompressEnd(&strm) != BZ_OK) { | 
|  | fprint(2, "bzip2: compress end failed (can't happen)\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | Bterm(&bin); | 
|  |  | 
|  | return 1; | 
|  | } |