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