aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/bzip2/bzip2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/bzip2/bzip2.c')
-rw-r--r--src/cmd/bzip2/bzip2.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/cmd/bzip2/bzip2.c b/src/cmd/bzip2/bzip2.c
new file mode 100644
index 00000000..17c2d06d
--- /dev/null
+++ b/src/cmd/bzip2/bzip2.c
@@ -0,0 +1,190 @@
+#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;
+
+ 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, "<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;
+}