OSDN Git Service

First pass at proper bunzip2 command line handling.
authorRob Landley <rob@landley.net>
Sun, 9 Aug 2015 00:21:42 +0000 (19:21 -0500)
committerRob Landley <rob@landley.net>
Sun, 9 Aug 2015 00:21:42 +0000 (19:21 -0500)
lib/lib.c
toys/other/bzcat.c

index 81c989a..4b87f8c 100644 (file)
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -575,7 +575,7 @@ void delete_tempfile(int fdin, int fdout, char **tempname)
 {
   close(fdin);
   close(fdout);
-  unlink(*tempname);
+  if (*tempname) unlink(*tempname);
   tempfile2zap = (char *)1;
   free(*tempname);
   *tempname = NULL;
index 642590d..850c51c 100644 (file)
@@ -1,4 +1,4 @@
-/* bzcat.c - decompress stdin to stdout using bunzip2.
+/* bzcat.c - bzip2 decompression
  *
  * Copyright 2003, 2007 Rob Landley <rob@landley.net>
  *
 
 
 USE_BZCAT(NEWTOY(bzcat, NULL, TOYFLAG_USR|TOYFLAG_BIN))
+USE_BUNZIP2(NEWTOY(bunzip2, "cftkv", TOYFLAG_USR|TOYFLAG_BIN))
+
+config BUNZIP2
+  bool "bunzip2"
+  default y
+  help
+    usage: bunzip2 [-cftkv] [FILE...]
+
+    Decompress listed files (file.bz becomes file) deleting archive file(s).
+    Read from stdin if no files listed.
+
+    -c force output to stdout
+    -f force decompression. (If FILE doesn't end in .bz, replace original.)
+    -k keep input files (-c and -t imply this)
+    -t  test integrity
+    -v verbose
 
 config BZCAT
   bool "bzcat"
   default y
   help
-    usage: bzcat [filename...]
+    usage: bzcat [FILE...]
 
     Decompress listed files to stdout. Use stdin if no files listed.
 */
 
+#define FOR_bunzip2
 #include "toys.h"
 
 #define THREADS 1
@@ -421,7 +438,7 @@ static int read_huffman_data(struct bunzip_data *bd, struct bwdata *bw)
 }
 
 // Flush output buffer to disk
-void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
+static void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
 {
   if (bd->outbufPos) {
     if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos)
@@ -430,7 +447,7 @@ void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd)
   }
 }
 
-void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
+static void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
 {
   int ii, jj;
   unsigned int *dbuf = bw->dbuf;
@@ -474,7 +491,7 @@ void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw)
 }
 
 // Decompress a block of text to intermediate buffer
-int read_bunzip_data(struct bunzip_data *bd)
+static int read_bunzip_data(struct bunzip_data *bd)
 {
   int rc = read_block_header(bd, bd->bwdata);
   if (!rc) rc=read_huffman_data(bd, bd->bwdata);
@@ -493,7 +510,8 @@ int read_bunzip_data(struct bunzip_data *bd)
 // http://dogma.net/markn/articles/bwt/bwt.htm
 // http://marknelson.us/1996/09/01/bwt/
 
-int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw, int out_fd, char *outbuf, int len)
+static int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw,
+  int out_fd, char *outbuf, int len)
 {
   unsigned int *dbuf = bw->dbuf;
   int count, pos, current, run, copies, outbyte, previous, gotcount = 0;
@@ -584,7 +602,8 @@ dataus_interruptus:
 
 // Allocate the structure, read file header. If !len, src_fd contains
 // filehandle to read from. Else inbuf contains data.
-int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len)
+static int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf,
+  int len)
 {
   struct bunzip_data *bd;
   unsigned int i;
@@ -622,10 +641,10 @@ int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len)
 
 // Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data,
 // not end of file.)
-void bunzipStream(int src_fd, int dst_fd)
+static char *bunzipStream(int src_fd, int dst_fd)
 {
   struct bunzip_data *bd;
-  char *bunzip_errors[]={NULL, "not bzip", "bad data", "old format"};
+  char *bunzip_errors[] = {0, "not bzip", "bad data", "old format"};
   int i, j;
 
   if (!(i = start_bunzip(&bd,src_fd, 0, 0))) {
@@ -636,15 +655,67 @@ void bunzipStream(int src_fd, int dst_fd)
 
   for (j=0; j<THREADS; j++) free(bd->bwdata[j].dbuf);
   free(bd);
-  if (i) error_exit(bunzip_errors[-i]);
+
+  return bunzip_errors[-i];
 }
 
 static void do_bzcat(int fd, char *name)
 {
-  bunzipStream(fd, 1);
+  char *err = bunzipStream(fd, 1);
+
+  if (err) error_exit(err);
 }
 
 void bzcat_main(void)
 {
   loopfiles(toys.optargs, do_bzcat);
 }
+
+static void do_bunzip2(int fd, char *name)
+{
+  int outfd = 1, rename = 0, len = strlen(name);
+  char *tmp, *err, *dotbz = 0;
+
+  // Trim off .bz or .bz2 extension
+  dotbz = name+len-3;
+  if ((len>3 && !strcmp(dotbz, ".bz")) || (len>4 && !strcmp(--dotbz, ".bz2")))
+    dotbz = 0;
+
+  // For - no replace
+  if (toys.optflags&FLAG_t) outfd = xopen("/dev/null", O_WRONLY);
+  else if ((fd || strcmp(name, "-")) && !(toys.optflags&FLAG_c)) {
+    if (toys.optflags&FLAG_k) {
+      if (!dotbz || !access(name, X_OK)) {
+        error_msg("%s exists", name);
+
+        return;
+      }
+    }
+    outfd = copy_tempfile(fd, name, &tmp);
+    rename++;
+  }
+
+  if (toys.optflags&FLAG_v) printf("%s:", name);
+  err = bunzipStream(fd, outfd);
+  if (toys.optflags&FLAG_v) {
+    printf("%s\n", err ? err : "ok");
+    toys.exitval |= !!err;
+  } else if (err) error_msg(err);
+
+  // can't test outfd==1 because may have been called with stdin+stdout closed
+  if (rename) {
+    if (toys.optflags&FLAG_k) {
+      free(tmp);
+      tmp = 0;
+    } else {
+      if (dotbz) *dotbz = '.';
+      if (!unlink(name)) perror_msg("%s", name);
+    }
+    (err ? delete_tempfile : replace_tempfile)(-1, outfd, &tmp);
+  }
+}
+
+void bunzip2_main(void)
+{
+  loopfiles(toys.optargs, do_bunzip2);
+}