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