#include #include #include #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; level = 6; stdout = 0; ARGBEGIN{ case 'D': debug++; break; case 'v': verbose++; break; case 'c': stdout++; 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, ""); }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; }