⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unzip.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <flate.h>#include "zip.h"enum{	BufSize	= 4096};static	int	cheader(Biobuf *bin, ZipHead *zh);static	int	copyout(int ofd, Biobuf *bin, long len);static	int	crcwrite(void *ofd, void *buf, int n);static	int	findCDir(Biobuf *bin, char *file);static	int	get1(Biobuf *b);static	int	get2(Biobuf *b);static	ulong	get4(Biobuf *b);static	char	*getname(Biobuf *b, int len);static	int	header(Biobuf *bin, ZipHead *zh);static	long	msdos2time(int time, int date);static	int	sunzip(Biobuf *bin);static	int	sunztable(Biobuf *bin);static	void	trailer(Biobuf *bin, ZipHead *zh);static	int	unzip(Biobuf *bin, char *file);static	int	unzipEntry(Biobuf *bin, ZipHead *czh);static	int	unztable(Biobuf *bin, char *file);static	int	wantFile(char *file);static	void	*emalloc(ulong);static	void	error(char*, ...);#pragma	varargck	argpos	error	1static	Biobuf	bin;static	ulong	crc;static	ulong	*crctab;static	int	debug;static	char	*delfile;static	int	lower;static	int	nwant;static	ulong	rlen;static	int	settimes;static	int	stdout;static	int	verbose;static	char	**want;static	int	wbad;static	ulong	wlen;static	jmp_buf	zjmp;static	jmp_buf	seekjmp;static voidusage(void){	fprint(2, "usage: unzip [-tsv] [-f zipfile] [file ...]\n");	exits("usage");}voidmain(int argc, char *argv[]){	char *zfile;	int fd, ok, table, stream;	table = 0;	stream = 0;	zfile = nil;	ARGBEGIN{	case 'D':		debug++;		break;	case 'c':		stdout++;		break;	case 'i':		lower++;		break;	case 'f':		zfile = ARGF();		if(zfile == nil)			usage();		break;	case 's':		stream++;		break;	case 't':		table++;		break;	case 'T':		settimes++;		break;	case 'v':		verbose++;		break;	default:		usage();		break;	}ARGEND	nwant = argc;	want = argv;	crctab = mkcrctab(ZCrcPoly);	ok = inflateinit();	if(ok != FlateOk)		sysfatal("inflateinit failed: %s\n", flateerr(ok));	if(zfile == nil){		Binit(&bin, 0, OREAD);		zfile = "<stdin>";	}else{		fd = open(zfile, OREAD);		if(fd < 0)			sysfatal("can't open %s: %r", zfile);		Binit(&bin, fd, OREAD);	}	if(setjmp(seekjmp)){		fprint(2, "trying to re-run assuming -s\n");		stream = 1;		Bseek(&bin, 0, 0);	}	if(table){		if(stream)			ok = sunztable(&bin);		else			ok = unztable(&bin, zfile);	}else{		if(stream)			ok = sunzip(&bin);		else			ok = unzip(&bin, zfile);	}	exits(ok ? nil: "errors");}/* * print the table of contents from the "central directory structure" */static intunztable(Biobuf *bin, char *file){	ZipHead zh;	int entries;	entries = findCDir(bin, file);	if(entries < 0)		return 0;	if(verbose > 1)		print("%d items in the archive\n", entries);	while(entries-- > 0){		if(setjmp(zjmp)){			free(zh.file);			return 0;		}		memset(&zh, 0, sizeof(zh));		if(!cheader(bin, &zh))			return 1;		if(wantFile(zh.file)){			if(verbose)				print("%-32s %10lud %s", zh.file, zh.uncsize, ctime(msdos2time(zh.modtime, zh.moddate)));			else				print("%s\n", zh.file);			if(verbose > 1){				print("\tmade by os %d vers %d.%d\n", zh.madeos, zh.madevers/10, zh.madevers % 10);				print("\textract by os %d vers %d.%d\n", zh.extos, zh.extvers/10, zh.extvers % 10);				print("\tflags %x\n", zh.flags);				print("\tmethod %d\n", zh.meth);				print("\tmod time %d\n", zh.modtime);				print("\tmod date %d\n", zh.moddate);				print("\tcrc %lux\n", zh.crc);				print("\tcompressed size %lud\n", zh.csize);				print("\tuncompressed size %lud\n", zh.uncsize);				print("\tinternal attributes %ux\n", zh.iattr);				print("\texternal attributes %lux\n", zh.eattr);				print("\tstarts at %ld\n", zh.off);			}		}		free(zh.file);		zh.file = nil;	}	return 1;}/* * print the "local file header" table of contents */static intsunztable(Biobuf *bin){	ZipHead zh;	vlong off;	ulong hcrc, hcsize, huncsize;	int ok, err;	ok = 1;	for(;;){		if(setjmp(zjmp)){			free(zh.file);			return 0;		}		memset(&zh, 0, sizeof(zh));		if(!header(bin, &zh))			return ok;		hcrc = zh.crc;		hcsize = zh.csize;		huncsize = zh.uncsize;		wlen = 0;		rlen = 0;		crc = 0;		wbad = 0;		if(zh.meth == 0){			if(!copyout(-1, bin, zh.csize))				error("reading data for %s failed: %r", zh.file);		}else if(zh.meth == 8){			off = Boffset(bin);			err = inflate((void*)-1, crcwrite, bin, (int(*)(void*))Bgetc);			if(err != FlateOk)				error("inflate %s failed: %s", zh.file, flateerr(err));			rlen = Boffset(bin) - off;		}else			error("can't handle compression method %d for %s", zh.meth, zh.file);		trailer(bin, &zh);		if(wantFile(zh.file)){			if(verbose)				print("%-32s %10lud %s", zh.file, zh.uncsize, ctime(msdos2time(zh.modtime, zh.moddate)));			else				print("%s\n", zh.file);			if(verbose > 1){				print("\textract by os %d vers %d.%d\n", zh.extos, zh.extvers / 10, zh.extvers % 10);				print("\tflags %x\n", zh.flags);				print("\tmethod %d\n", zh.meth);				print("\tmod time %d\n", zh.modtime);				print("\tmod date %d\n", zh.moddate);				print("\tcrc %lux\n", zh.crc);				print("\tcompressed size %lud\n", zh.csize);				print("\tuncompressed size %lud\n", zh.uncsize);				if((zh.flags & ZTrailInfo) && (hcrc || hcsize || huncsize)){					print("\theader crc %lux\n", zh.crc);					print("\theader compressed size %lud\n", zh.csize);					print("\theader uncompressed size %lud\n", zh.uncsize);				}			}		}		if(zh.crc != crc)			error("crc mismatch for %s", zh.file);		if(zh.uncsize != wlen)			error("output size mismatch for %s", zh.file);		if(zh.csize != rlen)			error("input size mismatch for %s", zh.file);		free(zh.file);		zh.file = nil;	}}/* * extract files using the info in the central directory structure */static intunzip(Biobuf *bin, char *file){	ZipHead zh;	vlong off;	int ok, eok, entries;	entries = findCDir(bin, file);	if(entries < 0)		return 0;	ok = 1;	while(entries-- > 0){		if(setjmp(zjmp)){			free(zh.file);			return 0;		}		memset(&zh, 0, sizeof(zh));		if(!cheader(bin, &zh))			return ok;		off = Boffset(bin);		if(wantFile(zh.file)){			if(Bseek(bin, zh.off, 0) < 0){				fprint(2, "unzip: can't seek to start of %s, skipping\n", zh.file);				ok = 0;			}else{				eok = unzipEntry(bin, &zh);				if(eok <= 0){					fprint(2, "unzip: skipping %s\n", zh.file);					ok = 0;				}			}		}		free(zh.file);		zh.file = nil;		if(Bseek(bin, off, 0) < 0){			fprint(2, "unzip: can't seek to start of next entry, terminating extraction\n");			return 0;		}	}	return ok;}/* * extract files using the info the "local file headers" */static intsunzip(Biobuf *bin){	int eok;	for(;;){		eok = unzipEntry(bin, nil);		if(eok == 0)			return 1;		if(eok < 0)			return 0;	}}/* * extracts a single entry from a zip file * czh is the optional corresponding central directory entry */static intunzipEntry(Biobuf *bin, ZipHead *czh){	Dir *d;	ZipHead zh;	char *p;	vlong off;	int fd, isdir, ok, err;	zh.file = nil;	if(setjmp(zjmp)){		delfile = nil;		free(zh.file);		return -1;	}	memset(&zh, 0, sizeof(zh));	if(!header(bin, &zh))		return 0;	ok = 1;	isdir = 0;	fd = -1;	if(wantFile(zh.file)){		if(verbose)			fprint(2, "extracting %s\n", zh.file);		if(czh != nil && czh->extos == ZDos){			isdir = czh->eattr & ZDDir;			if(isdir && zh.uncsize != 0)				fprint(2, "unzip: ignoring directory data for %s\n", zh.file);		}		if(zh.meth == 0 && zh.uncsize == 0){			p = strchr(zh.file, '\0');			if(p > zh.file && p[-1] == '/')				isdir = 1;		}		if(stdout){			if(ok && !isdir)				fd = 1;		}else if(isdir){			fd = create(zh.file, OREAD, DMDIR | 0775);			if(fd < 0){				d = dirstat(zh.file);				if(d == nil || (d->mode & DMDIR) != DMDIR){					fprint(2, "unzip: can't create directory %s: %r\n", zh.file);					ok = 0;				}				free(d);			}		}else if(ok){			fd = create(zh.file, OWRITE, 0664);			if(fd < 0){				fprint(2, "unzip: can't create %s: %r\n", zh.file);				ok = 0;			}else				delfile = zh.file;		}	}	wlen = 0;	rlen = 0;	crc = 0;	wbad = 0;	if(zh.meth == 0){		if(!copyout(fd, bin, zh.csize))			error("copying data for %s failed: %r", zh.file);	}else if(zh.meth == 8){		off = Boffset(bin);		err = inflate((void*)fd, crcwrite, bin, (int(*)(void*))Bgetc);		if(err != FlateOk)			error("inflate failed: %s", flateerr(err));		rlen = Boffset(bin) - off;	}else		error("can't handle compression method %d for %s", zh.meth, zh.file);	trailer(bin, &zh);	if(zh.crc != crc)		error("crc mismatch for %s", zh.file);	if(zh.uncsize != wlen)		error("output size mismatch for %s", zh.file);	if(zh.csize != rlen)		error("input size mismatch for %s", zh.file);	delfile = nil;	free(zh.file);	if(fd >= 0 && !stdout){		if(settimes){			d = dirfstat(fd);			if(d != nil){				d->mtime = msdos2time(zh.modtime, zh.moddate);				if(d->mtime)					dirfwstat(fd, d);			}		}		close(fd);	}	return ok;}static intwantFile(char *file){	int i, n;	if(nwant == 0)		return 1;	for(i = 0; i < nwant; i++){		if(strcmp(want[i], file) == 0)			return 1;		n = strlen(want[i]);		if(strncmp(want[i], file, n) == 0 && file[n] == '/')			return 1;	}	return 0;}/* * find the start of the central directory * returns the number of entries in the directory, * or -1 if there was an error */static intfindCDir(Biobuf *bin, char *file){	vlong ecoff;	long off, size, m;	int entries, zclen, dn, ds, de;	ecoff = Bseek(bin, -ZECHeadSize, 2);	if(ecoff < 0){		fprint(2, "unzip: can't seek to contents of %s\n", file);		longjmp(seekjmp, 1);		return -1;	}	if(setjmp(zjmp))		return -1;	if((m=get4(bin)) != ZECHeader){		fprint(2, "unzip: bad magic number for table of contents of %s: %#.8lx\n", file, m);		longjmp(seekjmp, 1);		return -1;	}	dn = get2(bin);	ds = get2(bin);	de = get2(bin);	entries = get2(bin);	size = get4(bin);	off = get4(bin);	zclen = get2(bin);	while(zclen-- > 0)		get1(bin);	if(verbose > 1){		print("table starts at %ld for %ld bytes\n", off, size);		if(ecoff - size != off)			print("\ttable should start at %lld-%ld=%lld\n", ecoff, size, ecoff-size);		if(dn || ds || de != entries)			print("\tcurrent disk=%d start disk=%d table entries on this disk=%d\n", dn, ds, de);	}	if(Bseek(bin, off, 0) != off){		fprint(2, "unzip: can't seek to start of contents of %s\n", file);		longjmp(seekjmp, 1);		return -1;	}	return entries;}static intcheader(Biobuf *bin, ZipHead *zh){	ulong v;	int flen, xlen, fclen;	v = get4(bin);	if(v != ZCHeader){		if(v == ZECHeader)			return 0;		error("bad magic number %lux", v);	}	zh->madevers = get1(bin);	zh->madeos = get1(bin);	zh->extvers = get1(bin);	zh->extos = get1(bin);	zh->flags = get2(bin);	zh->meth = get2(bin);	zh->modtime = get2(bin);	zh->moddate = get2(bin);	zh->crc = get4(bin);	zh->csize = get4(bin);	zh->uncsize = get4(bin);	flen = get2(bin);	xlen = get2(bin);	fclen = get2(bin);	get2(bin);		/* disk number start */	zh->iattr = get2(bin);	zh->eattr = get4(bin);	zh->off = get4(bin);	zh->file = getname(bin, flen);	while(xlen-- > 0)		get1(bin);	while(fclen-- > 0)		get1(bin);	return 1;}static intheader(Biobuf *bin, ZipHead *zh){	ulong v;	int flen, xlen;	v = get4(bin);	if(v != ZHeader){		if(v == ZCHeader)			return 0;		error("bad magic number %lux at %lld", v, Boffset(bin)-4);	}	zh->extvers = get1(bin);	zh->extos = get1(bin);	zh->flags = get2(bin);	zh->meth = get2(bin);	zh->modtime = get2(bin);	zh->moddate = get2(bin);	zh->crc = get4(bin);	zh->csize = get4(bin);	zh->uncsize = get4(bin);	flen = get2(bin);	xlen = get2(bin);	zh->file = getname(bin, flen);	while(xlen-- > 0)		get1(bin);	return 1;}static voidtrailer(Biobuf *bin, ZipHead *zh){	if(zh->flags & ZTrailInfo){		zh->crc = get4(bin);		zh->csize = get4(bin);		zh->uncsize = get4(bin);	}}static char*getname(Biobuf *bin, int len){	char *s;	int i, c;	s = emalloc(len + 1);	for(i = 0; i < len; i++){		c = get1(bin);		if(lower)			c = tolower(c);		s[i] = c;	}	s[i] = '\0';	return s;}static intcrcwrite(void *out, void *buf, int n){	int fd, nw;	wlen += n;	crc = blockcrc(crctab, crc, buf, n);	fd = (int)(uintptr)out;	if(fd < 0)		return n;	nw = write(fd, buf, n);	if(nw != n)		wbad = 1;	return nw;}static intcopyout(int ofd, Biobuf *bin, long len){	char buf[BufSize];	int n;	for(; len > 0; len -= n){		n = len;		if(n > BufSize)			n = BufSize;		n = Bread(bin, buf, n);		if(n <= 0)			return 0;		rlen += n;		if(crcwrite((void*)ofd, buf, n) != n)			return 0;	}	return 1;}static ulongget4(Biobuf *b){	ulong v;	int i, c;	v = 0;	for(i = 0; i < 4; i++){		c = Bgetc(b);		if(c < 0)			error("unexpected eof reading file information");		v |= c << (i * 8);	}	return v;}static intget2(Biobuf *b){	int i, c, v;	v = 0;	for(i = 0; i < 2; i++){		c = Bgetc(b);		if(c < 0)			error("unexpected eof reading file information");		v |= c << (i * 8);	}	return v;}static intget1(Biobuf *b){	int c;	c = Bgetc(b);	if(c < 0)		error("unexpected eof reading file information");	return c;}static longmsdos2time(int time, int date){	Tm tm;	tm.hour = time >> 11;	tm.min = (time >> 5) & 63;	tm.sec = (time & 31) << 1;	tm.year = 80 + (date >> 9);	tm.mon = ((date >> 5) & 15) - 1;	tm.mday = date & 31;	tm.zone[0] = '\0';	tm.yday = 0;	return tm2sec(&tm);}static void*emalloc(ulong n){	void *p;	p = malloc(n);	if(p == nil)		sysfatal("out of memory");	return p;}static voiderror(char *fmt, ...){	va_list arg;	fprint(2, "unzip: ");	va_start(arg, fmt);	vfprint(2, fmt, arg);	va_end(arg);	fprint(2, "\n");	if(delfile != nil){		fprint(2, "unzip: removing output file %s\n", delfile);		remove(delfile);		delfile = nil;	}	longjmp(zjmp, 1);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -