plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

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 }