URI:
       tbunzip2.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tbunzip2.c (3453B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include "bzlib.h"
            5 
            6 static        Biobuf        bin;
            7 static        int        debug;
            8 static        int        verbose;
            9 static        char        *delfile;
           10 static        char        *infile;
           11 static        int        bunzipf(char *file, int stdout);
           12 static        int        bunzip(int ofd, char *ofile, Biobuf *bin);
           13 
           14 void
           15 usage(void)
           16 {
           17         fprint(2, "usage: bunzip2 [-cvD] [file ...]\n");
           18         exits("usage");
           19 }
           20 
           21 void
           22 main(int argc, char **argv)
           23 {
           24         int i, ok, stdout;
           25 
           26         stdout = 0;
           27         ARGBEGIN{
           28         case 'D':
           29                 debug++;
           30                 break;
           31         case 'c':
           32                 stdout++;
           33                 break;
           34         case 'v':
           35                 verbose++;
           36                 break;
           37         }ARGEND
           38 
           39         if(argc == 0){
           40                 Binit(&bin, 0, OREAD);
           41                 infile = "<stdin>";
           42                 ok = bunzip(1, "<stdout>", &bin);
           43         }else{
           44                 ok = 1;
           45                 for(i = 0; i < argc; i++)
           46                         ok &= bunzipf(argv[i], stdout);
           47         }
           48 
           49         exits(ok ? nil: "errors");
           50 }
           51 
           52 static int
           53 bunzipf(char *file, int stdout)
           54 {
           55         char ofile[64], *s;
           56         int ofd, ifd, ok;
           57 
           58         infile = file;
           59         ifd = open(file, OREAD);
           60         if(ifd < 0){
           61                 fprint(2, "gunzip: can't open %s: %r\n", file);
           62                 return 0;
           63         }
           64 
           65         Binit(&bin, ifd, OREAD);
           66         if(Bgetc(&bin) != 'B' || Bgetc(&bin) != 'Z' || Bgetc(&bin) != 'h'){
           67                 fprint(2, "bunzip2: %s is not a bzip2 file\n", file);
           68                 Bterm(&bin);
           69                 close(ifd);
           70                 return 0;
           71         }
           72         Bungetc(&bin);
           73         Bungetc(&bin);
           74         Bungetc(&bin);
           75 
           76         if(stdout){
           77                 ofd = 1;
           78                 strcpy(ofile, "<stdout>");
           79         }else{
           80                 s = strrchr(file, '/');
           81                 if(s != nil)
           82                         s++;
           83                 else
           84                         s = file;
           85                 strecpy(ofile, ofile+sizeof ofile, s);
           86                 s = strrchr(ofile, '.');
           87                 if(s != nil && s != ofile && strcmp(s, ".bz2") == 0)
           88                         *s = '\0';
           89                 else if(s != nil && (strcmp(s, ".tbz") == 0 || strcmp(s, ".tbz2") == 0))
           90                         strcpy(s, ".tar");
           91                 else if(strcmp(file, ofile) == 0){
           92                         fprint(2, "bunzip2: can't overwrite %s\n", file);
           93                         Bterm(&bin);
           94                         close(ifd);
           95                         return 0;
           96                 }
           97 
           98                 ofd = create(ofile, OWRITE, 0666);
           99                 if(ofd < 0){
          100                         fprint(2, "bunzip2: can't create %s: %r\n", ofile);
          101                         Bterm(&bin);
          102                         close(ifd);
          103                         return 0;
          104                 }
          105                 delfile = ofile;
          106         }
          107 
          108         ok = bunzip(ofd, ofile, &bin);
          109         Bterm(&bin);
          110         close(ifd);
          111         if(!ok){
          112                 fprint(2, "bunzip2: can't write %s: %r\n", ofile);
          113                 if(delfile)
          114                         remove(delfile);
          115         }
          116         delfile = nil;
          117         if(!stdout && ofd >= 0)
          118                 close(ofd);
          119         return ok;
          120 }
          121 
          122 static int
          123 bunzip(int ofd, char *ofile, Biobuf *bin)
          124 {
          125         int e, n, done, onemore;
          126         char buf[8192];
          127         char obuf[8192];
          128         Biobuf bout;
          129         bz_stream strm;
          130 
          131         USED(ofile);
          132 
          133         memset(&strm, 0, sizeof strm);
          134         BZ2_bzDecompressInit(&strm, verbose, 0);
          135 
          136         strm.next_in = buf;
          137         strm.avail_in = 0;
          138         strm.next_out = obuf;
          139         strm.avail_out = sizeof obuf;
          140 
          141         done = 0;
          142         Binit(&bout, ofd, OWRITE);
          143 
          144         /*
          145          * onemore is a crummy hack to go 'round the loop
          146          * once after we finish, to flush the output buffer.
          147          */
          148         onemore = 1;
          149         SET(e);
          150         do {
          151                 if(!done && strm.avail_in < sizeof buf) {
          152                         if(strm.avail_in)
          153                                 memmove(buf, strm.next_in, strm.avail_in);
          154 
          155                         n = Bread(bin, buf+strm.avail_in, sizeof(buf)-strm.avail_in);
          156                         if(n <= 0)
          157                                 done = 1;
          158                         else
          159                                 strm.avail_in += n;
          160                         strm.next_in = buf;
          161                 }
          162                 if(strm.avail_out < sizeof obuf) {
          163                         Bwrite(&bout, obuf, sizeof(obuf)-strm.avail_out);
          164                         strm.next_out = obuf;
          165                         strm.avail_out = sizeof obuf;
          166                 }
          167                 if(onemore == 0)
          168                         break;
          169                 if(strm.avail_in == 0 && strm.avail_out == sizeof obuf)
          170                         break;
          171         } while((e=BZ2_bzDecompress(&strm)) == BZ_OK || onemore--);
          172 
          173         if(e != BZ_STREAM_END) {
          174                 fprint(2, "bunzip2: decompress failed\n");
          175                 return 0;
          176         }
          177 
          178         if(BZ2_bzDecompressEnd(&strm) != BZ_OK) {
          179                 fprint(2, "bunzip2: decompress end failed (can't happen)\n");
          180                 return 0;
          181         }
          182 
          183         Bterm(&bout);
          184 
          185         return 1;
          186 }