xref: /plan9/sys/src/cmd/gzip/unzip.c (revision ab28ad2a4e02e779ba816bd4ffb9e98fb557bade)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
480ee5cbfSDavid du Colombier #include <flate.h>
57dd7cddfSDavid du Colombier #include "zip.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier enum
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier 	BufSize	= 4096
107dd7cddfSDavid du Colombier };
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier static	int	cheader(Biobuf *bin, ZipHead *zh);
137dd7cddfSDavid du Colombier static	int	copyout(int ofd, Biobuf *bin, long len);
147dd7cddfSDavid du Colombier static	int	crcwrite(void *ofd, void *buf, int n);
157dd7cddfSDavid du Colombier static	int	findCDir(Biobuf *bin, char *file);
167dd7cddfSDavid du Colombier static	int	get1(Biobuf *b);
177dd7cddfSDavid du Colombier static	int	get2(Biobuf *b);
187dd7cddfSDavid du Colombier static	ulong	get4(Biobuf *b);
197dd7cddfSDavid du Colombier static	char	*getname(Biobuf *b, int len);
207dd7cddfSDavid du Colombier static	int	header(Biobuf *bin, ZipHead *zh);
217dd7cddfSDavid du Colombier static	long	msdos2time(int time, int date);
227dd7cddfSDavid du Colombier static	int	sunzip(Biobuf *bin);
237dd7cddfSDavid du Colombier static	int	sunztable(Biobuf *bin);
247dd7cddfSDavid du Colombier static	void	trailer(Biobuf *bin, ZipHead *zh);
257dd7cddfSDavid du Colombier static	int	unzip(Biobuf *bin, char *file);
267dd7cddfSDavid du Colombier static	int	unzipEntry(Biobuf *bin, ZipHead *czh);
277dd7cddfSDavid du Colombier static	int	unztable(Biobuf *bin, char *file);
287dd7cddfSDavid du Colombier static	int	wantFile(char *file);
297dd7cddfSDavid du Colombier 
307dd7cddfSDavid du Colombier static	void	*emalloc(ulong);
317dd7cddfSDavid du Colombier static	void	error(char*, ...);
327dd7cddfSDavid du Colombier #pragma	varargck	argpos	error	1
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier static	Biobuf	bin;
357dd7cddfSDavid du Colombier static	ulong	crc;
3680ee5cbfSDavid du Colombier static	ulong	*crctab;
377dd7cddfSDavid du Colombier static	int	debug;
387dd7cddfSDavid du Colombier static	char	*delfile;
397dd7cddfSDavid du Colombier static	int	lower;
407dd7cddfSDavid du Colombier static	int	nwant;
417dd7cddfSDavid du Colombier static	ulong	rlen;
427dd7cddfSDavid du Colombier static	int	settimes;
437dd7cddfSDavid du Colombier static	int	stdout;
447dd7cddfSDavid du Colombier static	int	verbose;
457dd7cddfSDavid du Colombier static	char	**want;
467dd7cddfSDavid du Colombier static	int	wbad;
477dd7cddfSDavid du Colombier static	ulong	wlen;
487dd7cddfSDavid du Colombier static	jmp_buf	zjmp;
49c03fc8d3SDavid du Colombier static	jmp_buf	seekjmp;
5021abd8f2SDavid du Colombier static	int	autodir;
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier static void
usage(void)537dd7cddfSDavid du Colombier usage(void)
547dd7cddfSDavid du Colombier {
55*ab28ad2aSDavid du Colombier 	fprint(2, "usage: unzip [-cistTvD] [-f zipfile] [file ...]\n");
567dd7cddfSDavid du Colombier 	exits("usage");
577dd7cddfSDavid du Colombier }
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier void
main(int argc,char * argv[])607dd7cddfSDavid du Colombier main(int argc, char *argv[])
617dd7cddfSDavid du Colombier {
627dd7cddfSDavid du Colombier 	char *zfile;
637dd7cddfSDavid du Colombier 	int fd, ok, table, stream;
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	table = 0;
667dd7cddfSDavid du Colombier 	stream = 0;
677dd7cddfSDavid du Colombier 	zfile = nil;
687dd7cddfSDavid du Colombier 	ARGBEGIN{
6921abd8f2SDavid du Colombier 	case 'a':
7021abd8f2SDavid du Colombier 		autodir++;
7121abd8f2SDavid du Colombier 		break;
727dd7cddfSDavid du Colombier 	case 'D':
737dd7cddfSDavid du Colombier 		debug++;
747dd7cddfSDavid du Colombier 		break;
757dd7cddfSDavid du Colombier 	case 'c':
767dd7cddfSDavid du Colombier 		stdout++;
777dd7cddfSDavid du Colombier 		break;
787dd7cddfSDavid du Colombier 	case 'i':
797dd7cddfSDavid du Colombier 		lower++;
807dd7cddfSDavid du Colombier 		break;
817dd7cddfSDavid du Colombier 	case 'f':
827dd7cddfSDavid du Colombier 		zfile = ARGF();
837dd7cddfSDavid du Colombier 		if(zfile == nil)
847dd7cddfSDavid du Colombier 			usage();
857dd7cddfSDavid du Colombier 		break;
867dd7cddfSDavid du Colombier 	case 's':
877dd7cddfSDavid du Colombier 		stream++;
887dd7cddfSDavid du Colombier 		break;
897dd7cddfSDavid du Colombier 	case 't':
907dd7cddfSDavid du Colombier 		table++;
917dd7cddfSDavid du Colombier 		break;
927dd7cddfSDavid du Colombier 	case 'T':
937dd7cddfSDavid du Colombier 		settimes++;
947dd7cddfSDavid du Colombier 		break;
957dd7cddfSDavid du Colombier 	case 'v':
967dd7cddfSDavid du Colombier 		verbose++;
977dd7cddfSDavid du Colombier 		break;
987dd7cddfSDavid du Colombier 	default:
997dd7cddfSDavid du Colombier 		usage();
1007dd7cddfSDavid du Colombier 		break;
1017dd7cddfSDavid du Colombier 	}ARGEND
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	nwant = argc;
1047dd7cddfSDavid du Colombier 	want = argv;
1057dd7cddfSDavid du Colombier 
10680ee5cbfSDavid du Colombier 	crctab = mkcrctab(ZCrcPoly);
10780ee5cbfSDavid du Colombier 	ok = inflateinit();
10880ee5cbfSDavid du Colombier 	if(ok != FlateOk)
10914cc0f53SDavid du Colombier 		sysfatal("inflateinit failed: %s", flateerr(ok));
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier 	if(zfile == nil){
1127dd7cddfSDavid du Colombier 		Binit(&bin, 0, OREAD);
1137dd7cddfSDavid du Colombier 		zfile = "<stdin>";
1147dd7cddfSDavid du Colombier 	}else{
1157dd7cddfSDavid du Colombier 		fd = open(zfile, OREAD);
1167dd7cddfSDavid du Colombier 		if(fd < 0)
1177dd7cddfSDavid du Colombier 			sysfatal("can't open %s: %r", zfile);
1187dd7cddfSDavid du Colombier 		Binit(&bin, fd, OREAD);
1197dd7cddfSDavid du Colombier 	}
1207dd7cddfSDavid du Colombier 
121c03fc8d3SDavid du Colombier 	if(setjmp(seekjmp)){
122c03fc8d3SDavid du Colombier 		fprint(2, "trying to re-run assuming -s\n");
123c03fc8d3SDavid du Colombier 		stream = 1;
124c03fc8d3SDavid du Colombier 		Bseek(&bin, 0, 0);
125c03fc8d3SDavid du Colombier 	}
126c03fc8d3SDavid du Colombier 
1277dd7cddfSDavid du Colombier 	if(table){
1287dd7cddfSDavid du Colombier 		if(stream)
1297dd7cddfSDavid du Colombier 			ok = sunztable(&bin);
1307dd7cddfSDavid du Colombier 		else
1317dd7cddfSDavid du Colombier 			ok = unztable(&bin, zfile);
1327dd7cddfSDavid du Colombier 	}else{
1337dd7cddfSDavid du Colombier 		if(stream)
1347dd7cddfSDavid du Colombier 			ok = sunzip(&bin);
1357dd7cddfSDavid du Colombier 		else
1367dd7cddfSDavid du Colombier 			ok = unzip(&bin, zfile);
1377dd7cddfSDavid du Colombier 	}
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier 	exits(ok ? nil: "errors");
1407dd7cddfSDavid du Colombier }
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier /*
1437dd7cddfSDavid du Colombier  * print the table of contents from the "central directory structure"
1447dd7cddfSDavid du Colombier  */
1457dd7cddfSDavid du Colombier static int
unztable(Biobuf * bin,char * file)1467dd7cddfSDavid du Colombier unztable(Biobuf *bin, char *file)
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier 	ZipHead zh;
1497dd7cddfSDavid du Colombier 	int entries;
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 	entries = findCDir(bin, file);
1527dd7cddfSDavid du Colombier 	if(entries < 0)
1537dd7cddfSDavid du Colombier 		return 0;
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	if(verbose > 1)
1567dd7cddfSDavid du Colombier 		print("%d items in the archive\n", entries);
1577dd7cddfSDavid du Colombier 	while(entries-- > 0){
1587dd7cddfSDavid du Colombier 		if(setjmp(zjmp)){
1597dd7cddfSDavid du Colombier 			free(zh.file);
1607dd7cddfSDavid du Colombier 			return 0;
1617dd7cddfSDavid du Colombier 		}
1627dd7cddfSDavid du Colombier 
1637dd7cddfSDavid du Colombier 		memset(&zh, 0, sizeof(zh));
1647dd7cddfSDavid du Colombier 		if(!cheader(bin, &zh))
1657dd7cddfSDavid du Colombier 			return 1;
1667dd7cddfSDavid du Colombier 
1677dd7cddfSDavid du Colombier 		if(wantFile(zh.file)){
1687dd7cddfSDavid du Colombier 			if(verbose)
1697dd7cddfSDavid du Colombier 				print("%-32s %10lud %s", zh.file, zh.uncsize, ctime(msdos2time(zh.modtime, zh.moddate)));
1707dd7cddfSDavid du Colombier 			else
1717dd7cddfSDavid du Colombier 				print("%s\n", zh.file);
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 			if(verbose > 1){
1747dd7cddfSDavid du Colombier 				print("\tmade by os %d vers %d.%d\n", zh.madeos, zh.madevers/10, zh.madevers % 10);
1757dd7cddfSDavid du Colombier 				print("\textract by os %d vers %d.%d\n", zh.extos, zh.extvers/10, zh.extvers % 10);
1767dd7cddfSDavid du Colombier 				print("\tflags %x\n", zh.flags);
1777dd7cddfSDavid du Colombier 				print("\tmethod %d\n", zh.meth);
1787dd7cddfSDavid du Colombier 				print("\tmod time %d\n", zh.modtime);
1797dd7cddfSDavid du Colombier 				print("\tmod date %d\n", zh.moddate);
1807dd7cddfSDavid du Colombier 				print("\tcrc %lux\n", zh.crc);
1817dd7cddfSDavid du Colombier 				print("\tcompressed size %lud\n", zh.csize);
1827dd7cddfSDavid du Colombier 				print("\tuncompressed size %lud\n", zh.uncsize);
1837dd7cddfSDavid du Colombier 				print("\tinternal attributes %ux\n", zh.iattr);
1847dd7cddfSDavid du Colombier 				print("\texternal attributes %lux\n", zh.eattr);
1857dd7cddfSDavid du Colombier 				print("\tstarts at %ld\n", zh.off);
1867dd7cddfSDavid du Colombier 			}
1877dd7cddfSDavid du Colombier 		}
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier 		free(zh.file);
1907dd7cddfSDavid du Colombier 		zh.file = nil;
1917dd7cddfSDavid du Colombier 	}
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier 	return 1;
1947dd7cddfSDavid du Colombier }
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier /*
1977dd7cddfSDavid du Colombier  * print the "local file header" table of contents
1987dd7cddfSDavid du Colombier  */
1997dd7cddfSDavid du Colombier static int
sunztable(Biobuf * bin)2007dd7cddfSDavid du Colombier sunztable(Biobuf *bin)
2017dd7cddfSDavid du Colombier {
2027dd7cddfSDavid du Colombier 	ZipHead zh;
2037dd7cddfSDavid du Colombier 	vlong off;
2047dd7cddfSDavid du Colombier 	ulong hcrc, hcsize, huncsize;
20580ee5cbfSDavid du Colombier 	int ok, err;
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	ok = 1;
2087dd7cddfSDavid du Colombier 	for(;;){
2097dd7cddfSDavid du Colombier 		if(setjmp(zjmp)){
2107dd7cddfSDavid du Colombier 			free(zh.file);
2117dd7cddfSDavid du Colombier 			return 0;
2127dd7cddfSDavid du Colombier 		}
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 		memset(&zh, 0, sizeof(zh));
2157dd7cddfSDavid du Colombier 		if(!header(bin, &zh))
2167dd7cddfSDavid du Colombier 			return ok;
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 		hcrc = zh.crc;
2197dd7cddfSDavid du Colombier 		hcsize = zh.csize;
2207dd7cddfSDavid du Colombier 		huncsize = zh.uncsize;
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 		wlen = 0;
2237dd7cddfSDavid du Colombier 		rlen = 0;
2247dd7cddfSDavid du Colombier 		crc = 0;
2257dd7cddfSDavid du Colombier 		wbad = 0;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier 		if(zh.meth == 0){
2287dd7cddfSDavid du Colombier 			if(!copyout(-1, bin, zh.csize))
2297dd7cddfSDavid du Colombier 				error("reading data for %s failed: %r", zh.file);
2307dd7cddfSDavid du Colombier 		}else if(zh.meth == 8){
2317dd7cddfSDavid du Colombier 			off = Boffset(bin);
23280ee5cbfSDavid du Colombier 			err = inflate((void*)-1, crcwrite, bin, (int(*)(void*))Bgetc);
23380ee5cbfSDavid du Colombier 			if(err != FlateOk)
23480ee5cbfSDavid du Colombier 				error("inflate %s failed: %s", zh.file, flateerr(err));
2357dd7cddfSDavid du Colombier 			rlen = Boffset(bin) - off;
2367dd7cddfSDavid du Colombier 		}else
2377dd7cddfSDavid du Colombier 			error("can't handle compression method %d for %s", zh.meth, zh.file);
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier 		trailer(bin, &zh);
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 		if(wantFile(zh.file)){
2427dd7cddfSDavid du Colombier 			if(verbose)
2437dd7cddfSDavid du Colombier 				print("%-32s %10lud %s", zh.file, zh.uncsize, ctime(msdos2time(zh.modtime, zh.moddate)));
2447dd7cddfSDavid du Colombier 			else
2457dd7cddfSDavid du Colombier 				print("%s\n", zh.file);
2467dd7cddfSDavid du Colombier 
2477dd7cddfSDavid du Colombier 			if(verbose > 1){
2487dd7cddfSDavid du Colombier 				print("\textract by os %d vers %d.%d\n", zh.extos, zh.extvers / 10, zh.extvers % 10);
2497dd7cddfSDavid du Colombier 				print("\tflags %x\n", zh.flags);
2507dd7cddfSDavid du Colombier 				print("\tmethod %d\n", zh.meth);
2517dd7cddfSDavid du Colombier 				print("\tmod time %d\n", zh.modtime);
2527dd7cddfSDavid du Colombier 				print("\tmod date %d\n", zh.moddate);
2537dd7cddfSDavid du Colombier 				print("\tcrc %lux\n", zh.crc);
2547dd7cddfSDavid du Colombier 				print("\tcompressed size %lud\n", zh.csize);
2557dd7cddfSDavid du Colombier 				print("\tuncompressed size %lud\n", zh.uncsize);
2567dd7cddfSDavid du Colombier 				if((zh.flags & ZTrailInfo) && (hcrc || hcsize || huncsize)){
2577dd7cddfSDavid du Colombier 					print("\theader crc %lux\n", zh.crc);
2587dd7cddfSDavid du Colombier 					print("\theader compressed size %lud\n", zh.csize);
2597dd7cddfSDavid du Colombier 					print("\theader uncompressed size %lud\n", zh.uncsize);
2607dd7cddfSDavid du Colombier 				}
2617dd7cddfSDavid du Colombier 			}
2627dd7cddfSDavid du Colombier 		}
2637dd7cddfSDavid du Colombier 
2647dd7cddfSDavid du Colombier 		if(zh.crc != crc)
2657dd7cddfSDavid du Colombier 			error("crc mismatch for %s", zh.file);
2667dd7cddfSDavid du Colombier 		if(zh.uncsize != wlen)
2677dd7cddfSDavid du Colombier 			error("output size mismatch for %s", zh.file);
2687dd7cddfSDavid du Colombier 		if(zh.csize != rlen)
2697dd7cddfSDavid du Colombier 			error("input size mismatch for %s", zh.file);
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 		free(zh.file);
2737dd7cddfSDavid du Colombier 		zh.file = nil;
2747dd7cddfSDavid du Colombier 	}
2757dd7cddfSDavid du Colombier }
2767dd7cddfSDavid du Colombier 
2777dd7cddfSDavid du Colombier /*
2787dd7cddfSDavid du Colombier  * extract files using the info in the central directory structure
2797dd7cddfSDavid du Colombier  */
2807dd7cddfSDavid du Colombier static int
unzip(Biobuf * bin,char * file)2817dd7cddfSDavid du Colombier unzip(Biobuf *bin, char *file)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	ZipHead zh;
2847dd7cddfSDavid du Colombier 	vlong off;
2857dd7cddfSDavid du Colombier 	int ok, eok, entries;
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier 	entries = findCDir(bin, file);
2887dd7cddfSDavid du Colombier 	if(entries < 0)
2897dd7cddfSDavid du Colombier 		return 0;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier 	ok = 1;
2927dd7cddfSDavid du Colombier 	while(entries-- > 0){
2937dd7cddfSDavid du Colombier 		if(setjmp(zjmp)){
2947dd7cddfSDavid du Colombier 			free(zh.file);
2957dd7cddfSDavid du Colombier 			return 0;
2967dd7cddfSDavid du Colombier 		}
2977dd7cddfSDavid du Colombier 		memset(&zh, 0, sizeof(zh));
2987dd7cddfSDavid du Colombier 		if(!cheader(bin, &zh))
2997dd7cddfSDavid du Colombier 			return ok;
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier 		off = Boffset(bin);
3037dd7cddfSDavid du Colombier 		if(wantFile(zh.file)){
3047dd7cddfSDavid du Colombier 			if(Bseek(bin, zh.off, 0) < 0){
3057dd7cddfSDavid du Colombier 				fprint(2, "unzip: can't seek to start of %s, skipping\n", zh.file);
3067dd7cddfSDavid du Colombier 				ok = 0;
3077dd7cddfSDavid du Colombier 			}else{
3087dd7cddfSDavid du Colombier 				eok = unzipEntry(bin, &zh);
3097dd7cddfSDavid du Colombier 				if(eok <= 0){
3107dd7cddfSDavid du Colombier 					fprint(2, "unzip: skipping %s\n", zh.file);
3117dd7cddfSDavid du Colombier 					ok = 0;
3127dd7cddfSDavid du Colombier 				}
3137dd7cddfSDavid du Colombier 			}
3147dd7cddfSDavid du Colombier 		}
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier 		free(zh.file);
3177dd7cddfSDavid du Colombier 		zh.file = nil;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 		if(Bseek(bin, off, 0) < 0){
3207dd7cddfSDavid du Colombier 			fprint(2, "unzip: can't seek to start of next entry, terminating extraction\n");
3217dd7cddfSDavid du Colombier 			return 0;
3227dd7cddfSDavid du Colombier 		}
3237dd7cddfSDavid du Colombier 	}
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier 	return ok;
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier /*
3297dd7cddfSDavid du Colombier  * extract files using the info the "local file headers"
3307dd7cddfSDavid du Colombier  */
3317dd7cddfSDavid du Colombier static int
sunzip(Biobuf * bin)3327dd7cddfSDavid du Colombier sunzip(Biobuf *bin)
3337dd7cddfSDavid du Colombier {
3347dd7cddfSDavid du Colombier 	int eok;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 	for(;;){
3377dd7cddfSDavid du Colombier 		eok = unzipEntry(bin, nil);
3387dd7cddfSDavid du Colombier 		if(eok == 0)
3397dd7cddfSDavid du Colombier 			return 1;
3407dd7cddfSDavid du Colombier 		if(eok < 0)
3417dd7cddfSDavid du Colombier 			return 0;
3427dd7cddfSDavid du Colombier 	}
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier 
34521abd8f2SDavid du Colombier static int mkdirs(char *);
34621abd8f2SDavid du Colombier 
34721abd8f2SDavid du Colombier /*
34821abd8f2SDavid du Colombier  * if any directories leading up to path don't exist, create them.
34921abd8f2SDavid du Colombier  * modifies but restores path.
35021abd8f2SDavid du Colombier  */
35121abd8f2SDavid du Colombier static int
mkpdirs(char * path)35221abd8f2SDavid du Colombier mkpdirs(char *path)
35321abd8f2SDavid du Colombier {
35421abd8f2SDavid du Colombier 	int rv = 0;
35521abd8f2SDavid du Colombier 	char *sl = strrchr(path, '/');
35621abd8f2SDavid du Colombier print("%s\n", path);
35721abd8f2SDavid du Colombier 	if (sl != nil) {
35821abd8f2SDavid du Colombier 		*sl = '\0';
35921abd8f2SDavid du Colombier 		rv = mkdirs(path);
36021abd8f2SDavid du Colombier 		*sl = '/';
36121abd8f2SDavid du Colombier 	}
36221abd8f2SDavid du Colombier 	return rv;
36321abd8f2SDavid du Colombier }
36421abd8f2SDavid du Colombier 
36521abd8f2SDavid du Colombier /*
36621abd8f2SDavid du Colombier  * if path or any directories leading up to it don't exist, create them.
36721abd8f2SDavid du Colombier  * modifies but restores path.
36821abd8f2SDavid du Colombier  */
36921abd8f2SDavid du Colombier static int
mkdirs(char * path)37021abd8f2SDavid du Colombier mkdirs(char *path)
37121abd8f2SDavid du Colombier {
37221abd8f2SDavid du Colombier 	int fd;
37321abd8f2SDavid du Colombier 
37421abd8f2SDavid du Colombier 	if (access(path, AEXIST) >= 0)
37521abd8f2SDavid du Colombier 		return 0;
37621abd8f2SDavid du Colombier 
37721abd8f2SDavid du Colombier 	/* make presumed-missing intermediate directories */
37821abd8f2SDavid du Colombier 	if (mkpdirs(path) < 0)
37921abd8f2SDavid du Colombier 		return -1;
38021abd8f2SDavid du Colombier 
38121abd8f2SDavid du Colombier 	/* make final directory */
38221abd8f2SDavid du Colombier 	fd = create(path, OREAD, 0755|DMDIR);
38321abd8f2SDavid du Colombier 	if (fd < 0)
38421abd8f2SDavid du Colombier 		/*
38521abd8f2SDavid du Colombier 		 * we may have lost a race; if the directory now exists,
38621abd8f2SDavid du Colombier 		 * it's okay.
38721abd8f2SDavid du Colombier 		 */
38821abd8f2SDavid du Colombier 		return access(path, AEXIST) < 0? -1: 0;
38921abd8f2SDavid du Colombier 	close(fd);
39021abd8f2SDavid du Colombier 	return 0;
39121abd8f2SDavid du Colombier }
39221abd8f2SDavid du Colombier 
39321abd8f2SDavid du Colombier 
3947dd7cddfSDavid du Colombier /*
3957dd7cddfSDavid du Colombier  * extracts a single entry from a zip file
3967dd7cddfSDavid du Colombier  * czh is the optional corresponding central directory entry
3977dd7cddfSDavid du Colombier  */
3987dd7cddfSDavid du Colombier static int
unzipEntry(Biobuf * bin,ZipHead * czh)3997dd7cddfSDavid du Colombier unzipEntry(Biobuf *bin, ZipHead *czh)
4007dd7cddfSDavid du Colombier {
4019a747e4fSDavid du Colombier 	Dir *d;
4027dd7cddfSDavid du Colombier 	ZipHead zh;
4037dd7cddfSDavid du Colombier 	char *p;
4047dd7cddfSDavid du Colombier 	vlong off;
40580ee5cbfSDavid du Colombier 	int fd, isdir, ok, err;
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier 	zh.file = nil;
4087dd7cddfSDavid du Colombier 	if(setjmp(zjmp)){
4097dd7cddfSDavid du Colombier 		delfile = nil;
4107dd7cddfSDavid du Colombier 		free(zh.file);
4117dd7cddfSDavid du Colombier 		return -1;
4127dd7cddfSDavid du Colombier 	}
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 	memset(&zh, 0, sizeof(zh));
4157dd7cddfSDavid du Colombier 	if(!header(bin, &zh))
4167dd7cddfSDavid du Colombier 		return 0;
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 	ok = 1;
4197dd7cddfSDavid du Colombier 	isdir = 0;
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier 	fd = -1;
4227dd7cddfSDavid du Colombier 	if(wantFile(zh.file)){
4237dd7cddfSDavid du Colombier 		if(verbose)
4247dd7cddfSDavid du Colombier 			fprint(2, "extracting %s\n", zh.file);
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 		if(czh != nil && czh->extos == ZDos){
4277dd7cddfSDavid du Colombier 			isdir = czh->eattr & ZDDir;
4287dd7cddfSDavid du Colombier 			if(isdir && zh.uncsize != 0)
4297dd7cddfSDavid du Colombier 				fprint(2, "unzip: ignoring directory data for %s\n", zh.file);
430d9dc5dd1SDavid du Colombier 		}
431d9dc5dd1SDavid du Colombier 		if(zh.meth == 0 && zh.uncsize == 0){
4327dd7cddfSDavid du Colombier 			p = strchr(zh.file, '\0');
4337dd7cddfSDavid du Colombier 			if(p > zh.file && p[-1] == '/')
4347dd7cddfSDavid du Colombier 				isdir = 1;
4357dd7cddfSDavid du Colombier 		}
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier 		if(stdout){
4387dd7cddfSDavid du Colombier 			if(ok && !isdir)
4397dd7cddfSDavid du Colombier 				fd = 1;
4407dd7cddfSDavid du Colombier 		}else if(isdir){
4419a747e4fSDavid du Colombier 			fd = create(zh.file, OREAD, DMDIR | 0775);
4427dd7cddfSDavid du Colombier 			if(fd < 0){
4439a747e4fSDavid du Colombier 				d = dirstat(zh.file);
4449a747e4fSDavid du Colombier 				if(d == nil || (d->mode & DMDIR) != DMDIR){
4457dd7cddfSDavid du Colombier 					fprint(2, "unzip: can't create directory %s: %r\n", zh.file);
4467dd7cddfSDavid du Colombier 					ok = 0;
4477dd7cddfSDavid du Colombier 				}
4489a747e4fSDavid du Colombier 				free(d);
4497dd7cddfSDavid du Colombier 			}
4507dd7cddfSDavid du Colombier 		}else if(ok){
45121abd8f2SDavid du Colombier 			if(autodir)
45221abd8f2SDavid du Colombier 				mkpdirs(zh.file);
4537dd7cddfSDavid du Colombier 			fd = create(zh.file, OWRITE, 0664);
4547dd7cddfSDavid du Colombier 			if(fd < 0){
4557dd7cddfSDavid du Colombier 				fprint(2, "unzip: can't create %s: %r\n", zh.file);
4567dd7cddfSDavid du Colombier 				ok = 0;
4577dd7cddfSDavid du Colombier 			}else
4587dd7cddfSDavid du Colombier 				delfile = zh.file;
4597dd7cddfSDavid du Colombier 		}
4607dd7cddfSDavid du Colombier 	}
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	wlen = 0;
4637dd7cddfSDavid du Colombier 	rlen = 0;
4647dd7cddfSDavid du Colombier 	crc = 0;
4657dd7cddfSDavid du Colombier 	wbad = 0;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	if(zh.meth == 0){
4687dd7cddfSDavid du Colombier 		if(!copyout(fd, bin, zh.csize))
4697dd7cddfSDavid du Colombier 			error("copying data for %s failed: %r", zh.file);
4707dd7cddfSDavid du Colombier 	}else if(zh.meth == 8){
4717dd7cddfSDavid du Colombier 		off = Boffset(bin);
47280ee5cbfSDavid du Colombier 		err = inflate((void*)fd, crcwrite, bin, (int(*)(void*))Bgetc);
47380ee5cbfSDavid du Colombier 		if(err != FlateOk)
47480ee5cbfSDavid du Colombier 			error("inflate failed: %s", flateerr(err));
4757dd7cddfSDavid du Colombier 		rlen = Boffset(bin) - off;
4767dd7cddfSDavid du Colombier 	}else
4777dd7cddfSDavid du Colombier 		error("can't handle compression method %d for %s", zh.meth, zh.file);
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	trailer(bin, &zh);
4807dd7cddfSDavid du Colombier 
4817dd7cddfSDavid du Colombier 	if(zh.crc != crc)
4827dd7cddfSDavid du Colombier 		error("crc mismatch for %s", zh.file);
4837dd7cddfSDavid du Colombier 	if(zh.uncsize != wlen)
4847dd7cddfSDavid du Colombier 		error("output size mismatch for %s", zh.file);
4857dd7cddfSDavid du Colombier 	if(zh.csize != rlen)
4867dd7cddfSDavid du Colombier 		error("input size mismatch for %s", zh.file);
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 	delfile = nil;
4897dd7cddfSDavid du Colombier 	free(zh.file);
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier 	if(fd >= 0 && !stdout){
4927dd7cddfSDavid du Colombier 		if(settimes){
4939a747e4fSDavid du Colombier 			d = dirfstat(fd);
4949a747e4fSDavid du Colombier 			if(d != nil){
4959a747e4fSDavid du Colombier 				d->mtime = msdos2time(zh.modtime, zh.moddate);
4969a747e4fSDavid du Colombier 				if(d->mtime)
4979a747e4fSDavid du Colombier 					dirfwstat(fd, d);
4987dd7cddfSDavid du Colombier 			}
4997dd7cddfSDavid du Colombier 		}
5007dd7cddfSDavid du Colombier 		close(fd);
5017dd7cddfSDavid du Colombier 	}
5027dd7cddfSDavid du Colombier 
5037dd7cddfSDavid du Colombier 	return ok;
5047dd7cddfSDavid du Colombier }
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier static int
wantFile(char * file)5077dd7cddfSDavid du Colombier wantFile(char *file)
5087dd7cddfSDavid du Colombier {
5097dd7cddfSDavid du Colombier 	int i, n;
5107dd7cddfSDavid du Colombier 
5117dd7cddfSDavid du Colombier 	if(nwant == 0)
5127dd7cddfSDavid du Colombier 		return 1;
5137dd7cddfSDavid du Colombier 	for(i = 0; i < nwant; i++){
5147dd7cddfSDavid du Colombier 		if(strcmp(want[i], file) == 0)
5157dd7cddfSDavid du Colombier 			return 1;
5167dd7cddfSDavid du Colombier 		n = strlen(want[i]);
5177dd7cddfSDavid du Colombier 		if(strncmp(want[i], file, n) == 0 && file[n] == '/')
5187dd7cddfSDavid du Colombier 			return 1;
5197dd7cddfSDavid du Colombier 	}
5207dd7cddfSDavid du Colombier 	return 0;
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier 
5237dd7cddfSDavid du Colombier /*
5247dd7cddfSDavid du Colombier  * find the start of the central directory
5257dd7cddfSDavid du Colombier  * returns the number of entries in the directory,
5267dd7cddfSDavid du Colombier  * or -1 if there was an error
5277dd7cddfSDavid du Colombier  */
5287dd7cddfSDavid du Colombier static int
findCDir(Biobuf * bin,char * file)5297dd7cddfSDavid du Colombier findCDir(Biobuf *bin, char *file)
5307dd7cddfSDavid du Colombier {
5317dd7cddfSDavid du Colombier 	vlong ecoff;
532c03fc8d3SDavid du Colombier 	long off, size, m;
5337dd7cddfSDavid du Colombier 	int entries, zclen, dn, ds, de;
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier 	ecoff = Bseek(bin, -ZECHeadSize, 2);
5367dd7cddfSDavid du Colombier 	if(ecoff < 0){
537c03fc8d3SDavid du Colombier 		fprint(2, "unzip: can't seek to contents of %s\n", file);
538c03fc8d3SDavid du Colombier 		longjmp(seekjmp, 1);
5397dd7cddfSDavid du Colombier 		return -1;
5407dd7cddfSDavid du Colombier 	}
5417dd7cddfSDavid du Colombier 	if(setjmp(zjmp))
5427dd7cddfSDavid du Colombier 		return -1;
5437dd7cddfSDavid du Colombier 
544c03fc8d3SDavid du Colombier 	if((m=get4(bin)) != ZECHeader){
545c03fc8d3SDavid du Colombier 		fprint(2, "unzip: bad magic number for table of contents of %s: %#.8lx\n", file, m);
546c03fc8d3SDavid du Colombier 		longjmp(seekjmp, 1);
5477dd7cddfSDavid du Colombier 		return -1;
5487dd7cddfSDavid du Colombier 	}
5497dd7cddfSDavid du Colombier 	dn = get2(bin);
5507dd7cddfSDavid du Colombier 	ds = get2(bin);
5517dd7cddfSDavid du Colombier 	de = get2(bin);
5527dd7cddfSDavid du Colombier 	entries = get2(bin);
5537dd7cddfSDavid du Colombier 	size = get4(bin);
5547dd7cddfSDavid du Colombier 	off = get4(bin);
5557dd7cddfSDavid du Colombier 	zclen = get2(bin);
5567dd7cddfSDavid du Colombier 	while(zclen-- > 0)
5577dd7cddfSDavid du Colombier 		get1(bin);
5587dd7cddfSDavid du Colombier 
5597dd7cddfSDavid du Colombier 	if(verbose > 1){
5607dd7cddfSDavid du Colombier 		print("table starts at %ld for %ld bytes\n", off, size);
5617dd7cddfSDavid du Colombier 		if(ecoff - size != off)
5627dd7cddfSDavid du Colombier 			print("\ttable should start at %lld-%ld=%lld\n", ecoff, size, ecoff-size);
5637dd7cddfSDavid du Colombier 		if(dn || ds || de != entries)
5647dd7cddfSDavid du Colombier 			print("\tcurrent disk=%d start disk=%d table entries on this disk=%d\n", dn, ds, de);
5657dd7cddfSDavid du Colombier 	}
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier 	if(Bseek(bin, off, 0) != off){
5687dd7cddfSDavid du Colombier 		fprint(2, "unzip: can't seek to start of contents of %s\n", file);
569c03fc8d3SDavid du Colombier 		longjmp(seekjmp, 1);
5707dd7cddfSDavid du Colombier 		return -1;
5717dd7cddfSDavid du Colombier 	}
5727dd7cddfSDavid du Colombier 
5737dd7cddfSDavid du Colombier 	return entries;
5747dd7cddfSDavid du Colombier }
5757dd7cddfSDavid du Colombier 
5767dd7cddfSDavid du Colombier static int
cheader(Biobuf * bin,ZipHead * zh)5777dd7cddfSDavid du Colombier cheader(Biobuf *bin, ZipHead *zh)
5787dd7cddfSDavid du Colombier {
5797dd7cddfSDavid du Colombier 	ulong v;
5807dd7cddfSDavid du Colombier 	int flen, xlen, fclen;
5817dd7cddfSDavid du Colombier 
5827dd7cddfSDavid du Colombier 	v = get4(bin);
5837dd7cddfSDavid du Colombier 	if(v != ZCHeader){
5847dd7cddfSDavid du Colombier 		if(v == ZECHeader)
5857dd7cddfSDavid du Colombier 			return 0;
5867dd7cddfSDavid du Colombier 		error("bad magic number %lux", v);
5877dd7cddfSDavid du Colombier 	}
5887dd7cddfSDavid du Colombier 	zh->madevers = get1(bin);
5897dd7cddfSDavid du Colombier 	zh->madeos = get1(bin);
5907dd7cddfSDavid du Colombier 	zh->extvers = get1(bin);
5917dd7cddfSDavid du Colombier 	zh->extos = get1(bin);
5927dd7cddfSDavid du Colombier 	zh->flags = get2(bin);
5937dd7cddfSDavid du Colombier 	zh->meth = get2(bin);
5947dd7cddfSDavid du Colombier 	zh->modtime = get2(bin);
5957dd7cddfSDavid du Colombier 	zh->moddate = get2(bin);
5967dd7cddfSDavid du Colombier 	zh->crc = get4(bin);
5977dd7cddfSDavid du Colombier 	zh->csize = get4(bin);
5987dd7cddfSDavid du Colombier 	zh->uncsize = get4(bin);
5997dd7cddfSDavid du Colombier 	flen = get2(bin);
6007dd7cddfSDavid du Colombier 	xlen = get2(bin);
6017dd7cddfSDavid du Colombier 	fclen = get2(bin);
6027dd7cddfSDavid du Colombier 	get2(bin);		/* disk number start */
6037dd7cddfSDavid du Colombier 	zh->iattr = get2(bin);
6047dd7cddfSDavid du Colombier 	zh->eattr = get4(bin);
6057dd7cddfSDavid du Colombier 	zh->off = get4(bin);
6067dd7cddfSDavid du Colombier 
6077dd7cddfSDavid du Colombier 	zh->file = getname(bin, flen);
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier 	while(xlen-- > 0)
6107dd7cddfSDavid du Colombier 		get1(bin);
6117dd7cddfSDavid du Colombier 
6127dd7cddfSDavid du Colombier 	while(fclen-- > 0)
6137dd7cddfSDavid du Colombier 		get1(bin);
6147dd7cddfSDavid du Colombier 
6157dd7cddfSDavid du Colombier 	return 1;
6167dd7cddfSDavid du Colombier }
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier static int
header(Biobuf * bin,ZipHead * zh)6197dd7cddfSDavid du Colombier header(Biobuf *bin, ZipHead *zh)
6207dd7cddfSDavid du Colombier {
6217dd7cddfSDavid du Colombier 	ulong v;
6227dd7cddfSDavid du Colombier 	int flen, xlen;
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier 	v = get4(bin);
6257dd7cddfSDavid du Colombier 	if(v != ZHeader){
6267dd7cddfSDavid du Colombier 		if(v == ZCHeader)
6277dd7cddfSDavid du Colombier 			return 0;
6287dd7cddfSDavid du Colombier 		error("bad magic number %lux at %lld", v, Boffset(bin)-4);
6297dd7cddfSDavid du Colombier 	}
6307dd7cddfSDavid du Colombier 	zh->extvers = get1(bin);
6317dd7cddfSDavid du Colombier 	zh->extos = get1(bin);
6327dd7cddfSDavid du Colombier 	zh->flags = get2(bin);
6337dd7cddfSDavid du Colombier 	zh->meth = get2(bin);
6347dd7cddfSDavid du Colombier 	zh->modtime = get2(bin);
6357dd7cddfSDavid du Colombier 	zh->moddate = get2(bin);
6367dd7cddfSDavid du Colombier 	zh->crc = get4(bin);
6377dd7cddfSDavid du Colombier 	zh->csize = get4(bin);
6387dd7cddfSDavid du Colombier 	zh->uncsize = get4(bin);
6397dd7cddfSDavid du Colombier 	flen = get2(bin);
6407dd7cddfSDavid du Colombier 	xlen = get2(bin);
6417dd7cddfSDavid du Colombier 
6427dd7cddfSDavid du Colombier 	zh->file = getname(bin, flen);
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 	while(xlen-- > 0)
6457dd7cddfSDavid du Colombier 		get1(bin);
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier 	return 1;
6487dd7cddfSDavid du Colombier }
6497dd7cddfSDavid du Colombier 
6507dd7cddfSDavid du Colombier static void
trailer(Biobuf * bin,ZipHead * zh)6517dd7cddfSDavid du Colombier trailer(Biobuf *bin, ZipHead *zh)
6527dd7cddfSDavid du Colombier {
6537dd7cddfSDavid du Colombier 	if(zh->flags & ZTrailInfo){
6547dd7cddfSDavid du Colombier 		zh->crc = get4(bin);
6557dd7cddfSDavid du Colombier 		zh->csize = get4(bin);
6567dd7cddfSDavid du Colombier 		zh->uncsize = get4(bin);
6577dd7cddfSDavid du Colombier 	}
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier 
6607dd7cddfSDavid du Colombier static char*
getname(Biobuf * bin,int len)6617dd7cddfSDavid du Colombier getname(Biobuf *bin, int len)
6627dd7cddfSDavid du Colombier {
6637dd7cddfSDavid du Colombier 	char *s;
6647dd7cddfSDavid du Colombier 	int i, c;
6657dd7cddfSDavid du Colombier 
6667dd7cddfSDavid du Colombier 	s = emalloc(len + 1);
6677dd7cddfSDavid du Colombier 	for(i = 0; i < len; i++){
6687dd7cddfSDavid du Colombier 		c = get1(bin);
6697dd7cddfSDavid du Colombier 		if(lower)
6707dd7cddfSDavid du Colombier 			c = tolower(c);
6717dd7cddfSDavid du Colombier 		s[i] = c;
6727dd7cddfSDavid du Colombier 	}
6737dd7cddfSDavid du Colombier 	s[i] = '\0';
6747dd7cddfSDavid du Colombier 	return s;
6757dd7cddfSDavid du Colombier }
6767dd7cddfSDavid du Colombier 
6777dd7cddfSDavid du Colombier static int
crcwrite(void * out,void * buf,int n)6787dd7cddfSDavid du Colombier crcwrite(void *out, void *buf, int n)
6797dd7cddfSDavid du Colombier {
6807dd7cddfSDavid du Colombier 	int fd, nw;
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier 	wlen += n;
68380ee5cbfSDavid du Colombier 	crc = blockcrc(crctab, crc, buf, n);
68474f16c81SDavid du Colombier 	fd = (int)(uintptr)out;
6857dd7cddfSDavid du Colombier 	if(fd < 0)
6867dd7cddfSDavid du Colombier 		return n;
6877dd7cddfSDavid du Colombier 	nw = write(fd, buf, n);
6887dd7cddfSDavid du Colombier 	if(nw != n)
6897dd7cddfSDavid du Colombier 		wbad = 1;
6907dd7cddfSDavid du Colombier 	return nw;
6917dd7cddfSDavid du Colombier }
6927dd7cddfSDavid du Colombier 
6937dd7cddfSDavid du Colombier static int
copyout(int ofd,Biobuf * bin,long len)6947dd7cddfSDavid du Colombier copyout(int ofd, Biobuf *bin, long len)
6957dd7cddfSDavid du Colombier {
6967dd7cddfSDavid du Colombier 	char buf[BufSize];
6977dd7cddfSDavid du Colombier 	int n;
6987dd7cddfSDavid du Colombier 
6997dd7cddfSDavid du Colombier 	for(; len > 0; len -= n){
7007dd7cddfSDavid du Colombier 		n = len;
7017dd7cddfSDavid du Colombier 		if(n > BufSize)
7027dd7cddfSDavid du Colombier 			n = BufSize;
7037dd7cddfSDavid du Colombier 		n = Bread(bin, buf, n);
7047dd7cddfSDavid du Colombier 		if(n <= 0)
7057dd7cddfSDavid du Colombier 			return 0;
7067dd7cddfSDavid du Colombier 		rlen += n;
7077dd7cddfSDavid du Colombier 		if(crcwrite((void*)ofd, buf, n) != n)
7087dd7cddfSDavid du Colombier 			return 0;
7097dd7cddfSDavid du Colombier 	}
7107dd7cddfSDavid du Colombier 	return 1;
7117dd7cddfSDavid du Colombier }
7127dd7cddfSDavid du Colombier 
7137dd7cddfSDavid du Colombier static ulong
get4(Biobuf * b)7147dd7cddfSDavid du Colombier get4(Biobuf *b)
7157dd7cddfSDavid du Colombier {
7167dd7cddfSDavid du Colombier 	ulong v;
7177dd7cddfSDavid du Colombier 	int i, c;
7187dd7cddfSDavid du Colombier 
7197dd7cddfSDavid du Colombier 	v = 0;
7207dd7cddfSDavid du Colombier 	for(i = 0; i < 4; i++){
7217dd7cddfSDavid du Colombier 		c = Bgetc(b);
7227dd7cddfSDavid du Colombier 		if(c < 0)
7237dd7cddfSDavid du Colombier 			error("unexpected eof reading file information");
7247dd7cddfSDavid du Colombier 		v |= c << (i * 8);
7257dd7cddfSDavid du Colombier 	}
7267dd7cddfSDavid du Colombier 	return v;
7277dd7cddfSDavid du Colombier }
7287dd7cddfSDavid du Colombier 
7297dd7cddfSDavid du Colombier static int
get2(Biobuf * b)7307dd7cddfSDavid du Colombier get2(Biobuf *b)
7317dd7cddfSDavid du Colombier {
7327dd7cddfSDavid du Colombier 	int i, c, v;
7337dd7cddfSDavid du Colombier 
7347dd7cddfSDavid du Colombier 	v = 0;
7357dd7cddfSDavid du Colombier 	for(i = 0; i < 2; i++){
7367dd7cddfSDavid du Colombier 		c = Bgetc(b);
7377dd7cddfSDavid du Colombier 		if(c < 0)
7387dd7cddfSDavid du Colombier 			error("unexpected eof reading file information");
7397dd7cddfSDavid du Colombier 		v |= c << (i * 8);
7407dd7cddfSDavid du Colombier 	}
7417dd7cddfSDavid du Colombier 	return v;
7427dd7cddfSDavid du Colombier }
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier static int
get1(Biobuf * b)7457dd7cddfSDavid du Colombier get1(Biobuf *b)
7467dd7cddfSDavid du Colombier {
7477dd7cddfSDavid du Colombier 	int c;
7487dd7cddfSDavid du Colombier 
7497dd7cddfSDavid du Colombier 	c = Bgetc(b);
7507dd7cddfSDavid du Colombier 	if(c < 0)
7517dd7cddfSDavid du Colombier 		error("unexpected eof reading file information");
7527dd7cddfSDavid du Colombier 	return c;
7537dd7cddfSDavid du Colombier }
7547dd7cddfSDavid du Colombier 
7557dd7cddfSDavid du Colombier static long
msdos2time(int time,int date)7567dd7cddfSDavid du Colombier msdos2time(int time, int date)
7577dd7cddfSDavid du Colombier {
7587dd7cddfSDavid du Colombier 	Tm tm;
7597dd7cddfSDavid du Colombier 
7607dd7cddfSDavid du Colombier 	tm.hour = time >> 11;
7617dd7cddfSDavid du Colombier 	tm.min = (time >> 5) & 63;
7627dd7cddfSDavid du Colombier 	tm.sec = (time & 31) << 1;
7637dd7cddfSDavid du Colombier 	tm.year = 80 + (date >> 9);
7647dd7cddfSDavid du Colombier 	tm.mon = ((date >> 5) & 15) - 1;
7657dd7cddfSDavid du Colombier 	tm.mday = date & 31;
7667dd7cddfSDavid du Colombier 	tm.zone[0] = '\0';
7676b6b9ac8SDavid du Colombier 	tm.yday = 0;
7687dd7cddfSDavid du Colombier 
7697dd7cddfSDavid du Colombier 	return tm2sec(&tm);
7707dd7cddfSDavid du Colombier }
7717dd7cddfSDavid du Colombier 
7727dd7cddfSDavid du Colombier static void*
emalloc(ulong n)7737dd7cddfSDavid du Colombier emalloc(ulong n)
7747dd7cddfSDavid du Colombier {
7757dd7cddfSDavid du Colombier 	void *p;
7767dd7cddfSDavid du Colombier 
7777dd7cddfSDavid du Colombier 	p = malloc(n);
7787dd7cddfSDavid du Colombier 	if(p == nil)
7797dd7cddfSDavid du Colombier 		sysfatal("out of memory");
7807dd7cddfSDavid du Colombier 	return p;
7817dd7cddfSDavid du Colombier }
7827dd7cddfSDavid du Colombier 
7837dd7cddfSDavid du Colombier static void
error(char * fmt,...)7847dd7cddfSDavid du Colombier error(char *fmt, ...)
7857dd7cddfSDavid du Colombier {
7867dd7cddfSDavid du Colombier 	va_list arg;
7877dd7cddfSDavid du Colombier 
7889a747e4fSDavid du Colombier 	fprint(2, "unzip: ");
7897dd7cddfSDavid du Colombier 	va_start(arg, fmt);
7909a747e4fSDavid du Colombier 	vfprint(2, fmt, arg);
7917dd7cddfSDavid du Colombier 	va_end(arg);
7929a747e4fSDavid du Colombier 	fprint(2, "\n");
7937dd7cddfSDavid du Colombier 
7947dd7cddfSDavid du Colombier 	if(delfile != nil){
7957dd7cddfSDavid du Colombier 		fprint(2, "unzip: removing output file %s\n", delfile);
7967dd7cddfSDavid du Colombier 		remove(delfile);
7977dd7cddfSDavid du Colombier 		delfile = nil;
7987dd7cddfSDavid du Colombier 	}
7997dd7cddfSDavid du Colombier 
8007dd7cddfSDavid du Colombier 	longjmp(zjmp, 1);
8017dd7cddfSDavid du Colombier }
802