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