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