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