bzip2.c 3.4 KB

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