gzip.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <flate.h>
  5. #include "gzip.h"
  6. static int gzipf(char*, int);
  7. static int gzip(char*, long, int, Biobuf*);
  8. static int crcread(void *fd, void *buf, int n);
  9. static int gzwrite(void *bout, void *buf, int n);
  10. static Biobuf bout;
  11. static ulong crc;
  12. static ulong *crctab;
  13. static int debug;
  14. static int eof;
  15. static int level;
  16. static ulong totr;
  17. static int verbose;
  18. void
  19. usage(void)
  20. {
  21. fprint(2, "usage: gzip [-vcD] [-1-9] [file ...]\n");
  22. exits("usage");
  23. }
  24. void
  25. main(int argc, char *argv[])
  26. {
  27. int i, ok, stdout;
  28. level = 6;
  29. stdout = 0;
  30. ARGBEGIN{
  31. case 'D':
  32. debug++;
  33. break;
  34. case 'v':
  35. verbose++;
  36. break;
  37. case 'c':
  38. stdout = 1;
  39. break;
  40. case '1': case '2': case '3': case '4':
  41. case '5': case '6': case '7': case '8': case '9':
  42. level = ARGC() - '0';
  43. break;
  44. default:
  45. usage();
  46. break;
  47. }ARGEND
  48. crctab = mkcrctab(GZCRCPOLY);
  49. ok = deflateinit();
  50. if(ok != FlateOk)
  51. sysfatal("deflateinit failed: %s\n", flateerr(ok));
  52. if(argc == 0){
  53. Binit(&bout, 1, OWRITE);
  54. ok = gzip(nil, time(0), 0, &bout);
  55. Bterm(&bout);
  56. }else{
  57. ok = 1;
  58. for(i = 0; i < argc; i++)
  59. ok &= gzipf(argv[i], stdout);
  60. }
  61. exits(ok ? nil: "errors");
  62. }
  63. static int
  64. gzipf(char *file, int stdout)
  65. {
  66. Dir *dir;
  67. char ofile[256], *f, *s;
  68. int ifd, ofd, ok;
  69. ifd = open(file, OREAD);
  70. if(ifd < 0){
  71. fprint(2, "gzip: can't open %s: %r\n", file);
  72. return 0;
  73. }
  74. dir = dirfstat(ifd);
  75. if(dir == nil){
  76. fprint(2, "gzip: can't stat %s: %r\n", file);
  77. close(ifd);
  78. return 0;
  79. }
  80. if(dir->mode & DMDIR){
  81. fprint(2, "gzip: can't compress a directory\n");
  82. close(ifd);
  83. free(dir);
  84. return 0;
  85. }
  86. if(stdout){
  87. ofd = 1;
  88. strcpy(ofile, "<stdout>");
  89. }else{
  90. f = strrchr(file, '/');
  91. if(f != nil)
  92. f++;
  93. else
  94. f = file;
  95. s = strrchr(f, '.');
  96. if(s != nil && s != ofile && strcmp(s, ".tar") == 0){
  97. *s = '\0';
  98. snprint(ofile, sizeof(ofile), "%s.tgz", f);
  99. }else
  100. snprint(ofile, sizeof(ofile), "%s.gz", f);
  101. ofd = create(ofile, OWRITE, 0666);
  102. if(ofd < 0){
  103. fprint(2, "gzip: can't open %s: %r\n", ofile);
  104. close(ifd);
  105. return 0;
  106. }
  107. }
  108. if(verbose)
  109. fprint(2, "compressing %s to %s\n", file, ofile);
  110. Binit(&bout, ofd, OWRITE);
  111. ok = gzip(file, dir->mtime, ifd, &bout);
  112. if(!ok || Bflush(&bout) < 0){
  113. fprint(2, "gzip: error writing %s: %r\n", ofile);
  114. if(!stdout)
  115. remove(ofile);
  116. }
  117. Bterm(&bout);
  118. free(dir);
  119. close(ifd);
  120. close(ofd);
  121. return ok;
  122. }
  123. static int
  124. gzip(char *file, long mtime, int ifd, Biobuf *bout)
  125. {
  126. int flags, err;
  127. flags = 0;
  128. Bputc(bout, GZMAGIC1);
  129. Bputc(bout, GZMAGIC2);
  130. Bputc(bout, GZDEFLATE);
  131. if(file != nil)
  132. flags |= GZFNAME;
  133. Bputc(bout, flags);
  134. Bputc(bout, mtime);
  135. Bputc(bout, mtime>>8);
  136. Bputc(bout, mtime>>16);
  137. Bputc(bout, mtime>>24);
  138. Bputc(bout, 0);
  139. Bputc(bout, GZOSINFERNO);
  140. if(flags & GZFNAME)
  141. Bwrite(bout, file, strlen(file)+1);
  142. crc = 0;
  143. eof = 0;
  144. totr = 0;
  145. err = deflate(bout, gzwrite, (void*)ifd, crcread, level, debug);
  146. if(err != FlateOk){
  147. fprint(2, "gzip: deflate failed: %s\n", flateerr(err));
  148. return 0;
  149. }
  150. Bputc(bout, crc);
  151. Bputc(bout, crc>>8);
  152. Bputc(bout, crc>>16);
  153. Bputc(bout, crc>>24);
  154. Bputc(bout, totr);
  155. Bputc(bout, totr>>8);
  156. Bputc(bout, totr>>16);
  157. Bputc(bout, totr>>24);
  158. return 1;
  159. }
  160. static int
  161. crcread(void *fd, void *buf, int n)
  162. {
  163. int nr, m;
  164. nr = 0;
  165. for(; !eof && n > 0; n -= m){
  166. m = read((int)fd, (char*)buf+nr, n);
  167. if(m <= 0){
  168. eof = 1;
  169. if(m < 0)
  170. return -1;
  171. break;
  172. }
  173. nr += m;
  174. }
  175. crc = blockcrc(crctab, crc, buf, nr);
  176. totr += nr;
  177. return nr;
  178. }
  179. static int
  180. gzwrite(void *bout, void *buf, int n)
  181. {
  182. if(n != Bwrite(bout, buf, n)){
  183. eof = 1;
  184. return -1;
  185. }
  186. return n;
  187. }