bunzip2.c 3.4 KB

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