xref: /plan9/sys/src/cmd/disk/mkext.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier enum{
63e12c5d1SDavid du Colombier 	LEN	= 8*1024,
7*219b2ee8SDavid du Colombier 	NFLDS	= 6,		/* filename, modes, uid, gid, mtime, bytes */
83e12c5d1SDavid du Colombier };
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier int	selected(char*, int, char*[]);
113e12c5d1SDavid du Colombier void	mkdirs(char*, char*);
12*219b2ee8SDavid du Colombier void	mkdir(char*, ulong, ulong, char*, char*);
13*219b2ee8SDavid du Colombier void	extract(char*, ulong, ulong, char*, char*, ulong);
143e12c5d1SDavid du Colombier void	seekpast(ulong);
153e12c5d1SDavid du Colombier void	error(char*, ...);
163e12c5d1SDavid du Colombier void	warn(char*, ...);
173e12c5d1SDavid du Colombier void	usage(void);
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier Biobufhdr bin;
203e12c5d1SDavid du Colombier uchar	binbuf[2*LEN];
213e12c5d1SDavid du Colombier int	uflag;
223e12c5d1SDavid du Colombier int	hflag;
23*219b2ee8SDavid du Colombier int	vflag;
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier void
263e12c5d1SDavid du Colombier main(int argc, char **argv)
273e12c5d1SDavid du Colombier {
283e12c5d1SDavid du Colombier 	Biobuf bout;
293e12c5d1SDavid du Colombier 	char *fields[NFLDS], name[2*LEN], *p, *namep;
303e12c5d1SDavid du Colombier 	char uid[NAMELEN], gid[NAMELEN];
31*219b2ee8SDavid du Colombier 	ulong mode, bytes, mtime;
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier 	namep = name;
343e12c5d1SDavid du Colombier 	ARGBEGIN{
353e12c5d1SDavid du Colombier 	case 'd':
363e12c5d1SDavid du Colombier 		p = ARGF();
373e12c5d1SDavid du Colombier 		if(strlen(p) >= LEN)
383e12c5d1SDavid du Colombier 			error("destination fs name too long\n");
393e12c5d1SDavid du Colombier 		strcpy(name, p);
403e12c5d1SDavid du Colombier 		namep = name + strlen(name);
413e12c5d1SDavid du Colombier 		break;
423e12c5d1SDavid du Colombier 	case 'h':
433e12c5d1SDavid du Colombier 		hflag = 1;
443e12c5d1SDavid du Colombier 		Binit(&bout, 1, OWRITE);
453e12c5d1SDavid du Colombier 		break;
463e12c5d1SDavid du Colombier 	case 'u':
473e12c5d1SDavid du Colombier 		uflag = 1;
483e12c5d1SDavid du Colombier 		break;
49*219b2ee8SDavid du Colombier 	case 'v':
50*219b2ee8SDavid du Colombier 		vflag = 1;
51*219b2ee8SDavid du Colombier 		break;
523e12c5d1SDavid du Colombier 	default:
533e12c5d1SDavid du Colombier 		usage();
543e12c5d1SDavid du Colombier 	}ARGEND
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier 	Binits(&bin, 0, OREAD, binbuf, sizeof binbuf);
573e12c5d1SDavid du Colombier 	while(p = Brdline(&bin, '\n')){
583e12c5d1SDavid du Colombier 		p[Blinelen(&bin)-1] = '\0';
593e12c5d1SDavid du Colombier 		if(strcmp(p, "end of archive") == 0){
603e12c5d1SDavid du Colombier 			fprint(2, "done\n");
613e12c5d1SDavid du Colombier 			exits(0);
623e12c5d1SDavid du Colombier 		}
633e12c5d1SDavid du Colombier 		if(getfields(p, fields, NFLDS) != NFLDS){
643e12c5d1SDavid du Colombier 			warn("too few fields in file header");
653e12c5d1SDavid du Colombier 			continue;
663e12c5d1SDavid du Colombier 		}
673e12c5d1SDavid du Colombier 		strcpy(namep, fields[0]);
683e12c5d1SDavid du Colombier 		mode = strtoul(fields[1], 0, 8);
69*219b2ee8SDavid du Colombier 		mtime = strtoul(fields[4], 0, 10);
70*219b2ee8SDavid du Colombier 		bytes = strtoul(fields[5], 0, 10);
713e12c5d1SDavid du Colombier 		strncpy(uid, fields[2], NAMELEN);
723e12c5d1SDavid du Colombier 		strncpy(gid, fields[3], NAMELEN);
733e12c5d1SDavid du Colombier 		if(argc){
743e12c5d1SDavid du Colombier 			if(!selected(namep, argc, argv)){
753e12c5d1SDavid du Colombier 				if(bytes)
763e12c5d1SDavid du Colombier 					seekpast(bytes);
773e12c5d1SDavid du Colombier 				continue;
783e12c5d1SDavid du Colombier 			}
793e12c5d1SDavid du Colombier 			mkdirs(name, namep);
803e12c5d1SDavid du Colombier 		}
813e12c5d1SDavid du Colombier 		if(hflag){
82*219b2ee8SDavid du Colombier 			Bprint(&bout, "%s %luo %s %s %lud %d\n",
83*219b2ee8SDavid du Colombier 				name, mode, uid, gid, mtime, bytes);
843e12c5d1SDavid du Colombier 			if(bytes)
853e12c5d1SDavid du Colombier 				seekpast(bytes);
863e12c5d1SDavid du Colombier 			continue;
873e12c5d1SDavid du Colombier 		}
883e12c5d1SDavid du Colombier 		if(mode & CHDIR)
89*219b2ee8SDavid du Colombier 			mkdir(name, mode, mtime, uid, gid);
903e12c5d1SDavid du Colombier 		else
91*219b2ee8SDavid du Colombier 			extract(name, mode, mtime, uid, gid, bytes);
923e12c5d1SDavid du Colombier 	}
933e12c5d1SDavid du Colombier 	fprint(2, "premature end of archive\n");
943e12c5d1SDavid du Colombier 	exits("premature end of archive");
953e12c5d1SDavid du Colombier }
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier int
983e12c5d1SDavid du Colombier fileprefix(char *prefix, char *s)
993e12c5d1SDavid du Colombier {
1003e12c5d1SDavid du Colombier 	while(*prefix)
1013e12c5d1SDavid du Colombier 		if(*prefix++ != *s++)
1023e12c5d1SDavid du Colombier 			return 0;
1033e12c5d1SDavid du Colombier 	if(*s && *s != '/')
1043e12c5d1SDavid du Colombier 		return 0;
1053e12c5d1SDavid du Colombier 	return 1;
1063e12c5d1SDavid du Colombier }
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier int
1093e12c5d1SDavid du Colombier selected(char *s, int argc, char *argv[])
1103e12c5d1SDavid du Colombier {
1113e12c5d1SDavid du Colombier 	int i;
1123e12c5d1SDavid du Colombier 
1133e12c5d1SDavid du Colombier 	for(i=0; i<argc; i++)
1143e12c5d1SDavid du Colombier 		if(fileprefix(argv[i], s))
1153e12c5d1SDavid du Colombier 			return 1;
1163e12c5d1SDavid du Colombier 	return 0;
1173e12c5d1SDavid du Colombier }
1183e12c5d1SDavid du Colombier 
1193e12c5d1SDavid du Colombier void
1203e12c5d1SDavid du Colombier mkdirs(char *name, char *namep)
1213e12c5d1SDavid du Colombier {
1223e12c5d1SDavid du Colombier 	char buf[2*LEN], *p;
1233e12c5d1SDavid du Colombier 	int fd;
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier 	strcpy(buf, name);
1263e12c5d1SDavid du Colombier 	for(p = &buf[namep - name]; p = utfrune(p, '/'); p++){
1273e12c5d1SDavid du Colombier 		if(p[1] == '\0')
1283e12c5d1SDavid du Colombier 			return;
1293e12c5d1SDavid du Colombier 		*p = 0;
1303e12c5d1SDavid du Colombier 		fd = create(buf, OREAD, 0775|CHDIR);
1313e12c5d1SDavid du Colombier 		close(fd);
1323e12c5d1SDavid du Colombier 		*p = '/';
1333e12c5d1SDavid du Colombier 	}
1343e12c5d1SDavid du Colombier }
1353e12c5d1SDavid du Colombier 
1363e12c5d1SDavid du Colombier void
137*219b2ee8SDavid du Colombier mkdir(char *name, ulong mode, ulong mtime, char *uid, char *gid)
1383e12c5d1SDavid du Colombier {
1393e12c5d1SDavid du Colombier 	Dir d;
1403e12c5d1SDavid du Colombier 	int fd;
1413e12c5d1SDavid du Colombier 	char *p;
1423e12c5d1SDavid du Colombier 
1433e12c5d1SDavid du Colombier 	fd = create(name, OREAD, mode);
1443e12c5d1SDavid du Colombier 	if(fd < 0){
1453e12c5d1SDavid du Colombier 		if(dirstat(name, &d) < 0 || !(d.mode & CHDIR)){
1463e12c5d1SDavid du Colombier 			warn("can't make directory %s: %r", name);
1473e12c5d1SDavid du Colombier 			return;
1483e12c5d1SDavid du Colombier 		}
1493e12c5d1SDavid du Colombier 	}else if(dirfstat(fd, &d) < 0)
150*219b2ee8SDavid du Colombier 		warn("can't stat %s: %r", name);
1513e12c5d1SDavid du Colombier 	close(fd);
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 	p = utfrrune(name, L'/');
1543e12c5d1SDavid du Colombier 	if(p)
1553e12c5d1SDavid du Colombier 		p++;
1563e12c5d1SDavid du Colombier 	else
1573e12c5d1SDavid du Colombier 		p = name;
1583e12c5d1SDavid du Colombier 	strncpy(d.name, p, NAMELEN);
1593e12c5d1SDavid du Colombier 	if(uflag){
1603e12c5d1SDavid du Colombier 		strncpy(d.uid, uid, NAMELEN);
1613e12c5d1SDavid du Colombier 		strncpy(d.gid, gid, NAMELEN);
162*219b2ee8SDavid du Colombier 		d.mtime = mtime;
1633e12c5d1SDavid du Colombier 	}
1643e12c5d1SDavid du Colombier 	d.mode = mode;
1653e12c5d1SDavid du Colombier 	if(dirwstat(name, &d) < 0)
1663e12c5d1SDavid du Colombier 		warn("can't set modes for %s: %r", name);
1673e12c5d1SDavid du Colombier 	if(uflag){
1683e12c5d1SDavid du Colombier 		if(dirstat(name, &d) < 0)
1693e12c5d1SDavid du Colombier 			warn("can't reread modes for %s: %r", name);
170*219b2ee8SDavid du Colombier 		if(d.mtime != mtime)
171*219b2ee8SDavid du Colombier 			warn("%s: time mismatch %lud %lud\n", name, mtime, d.mtime);
1723e12c5d1SDavid du Colombier 		if(strcmp(uid, d.uid))
1733e12c5d1SDavid du Colombier 			warn("%s: uid mismatch %s %s", name, uid, d.uid);
1743e12c5d1SDavid du Colombier 		if(strcmp(gid, d.gid))
1753e12c5d1SDavid du Colombier 			warn("%s: gid mismatch %s %s", name, gid, d.gid);
1763e12c5d1SDavid du Colombier 	}
1773e12c5d1SDavid du Colombier 	close(fd);
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier void
181*219b2ee8SDavid du Colombier extract(char *name, ulong mode, ulong mtime, char *uid, char *gid, ulong bytes)
1823e12c5d1SDavid du Colombier {
1833e12c5d1SDavid du Colombier 	Dir d;
1843e12c5d1SDavid du Colombier 	Biobuf *b;
1853e12c5d1SDavid du Colombier 	char buf[LEN];
1863e12c5d1SDavid du Colombier 	char *p;
1873e12c5d1SDavid du Colombier 	ulong n, tot;
1883e12c5d1SDavid du Colombier 
189*219b2ee8SDavid du Colombier 	if(vflag)
190*219b2ee8SDavid du Colombier 		print("x %s %d bytes\n", name, bytes);
191*219b2ee8SDavid du Colombier 
1923e12c5d1SDavid du Colombier 	b = Bopen(name, OWRITE);
1933e12c5d1SDavid du Colombier 	if(!b){
1943e12c5d1SDavid du Colombier 		warn("can't make file %s: %r", name);
1953e12c5d1SDavid du Colombier 		seekpast(bytes);
1963e12c5d1SDavid du Colombier 		return;
1973e12c5d1SDavid du Colombier 	}
1983e12c5d1SDavid du Colombier 	for(tot = 0; tot < bytes; tot += n){
1993e12c5d1SDavid du Colombier 		n = sizeof buf;
2003e12c5d1SDavid du Colombier 		if(tot + n > bytes)
2013e12c5d1SDavid du Colombier 			n = bytes - tot;
2023e12c5d1SDavid du Colombier 		n = Bread(&bin, buf, n);
203*219b2ee8SDavid du Colombier 		if(n <= 0)
2043e12c5d1SDavid du Colombier 			error("premature eof reading %s", name);
2053e12c5d1SDavid du Colombier 		if(Bwrite(b, buf, n) != n)
2063e12c5d1SDavid du Colombier 			warn("error writing %s: %r", name);
2073e12c5d1SDavid du Colombier 	}
2083e12c5d1SDavid du Colombier 
2093e12c5d1SDavid du Colombier 	if(dirfstat(Bfildes(b), &d) < 0)
210*219b2ee8SDavid du Colombier 		warn("can't stat %s: %r", name);
2113e12c5d1SDavid du Colombier 	p = utfrrune(name, '/');
2123e12c5d1SDavid du Colombier 	if(p)
2133e12c5d1SDavid du Colombier 		p++;
2143e12c5d1SDavid du Colombier 	else
2153e12c5d1SDavid du Colombier 		p = name;
2163e12c5d1SDavid du Colombier 	strncpy(d.name, p, NAMELEN);
2173e12c5d1SDavid du Colombier 	if(uflag){
2183e12c5d1SDavid du Colombier 		strncpy(d.uid, uid, NAMELEN);
2193e12c5d1SDavid du Colombier 		strncpy(d.gid, gid, NAMELEN);
220*219b2ee8SDavid du Colombier 		d.mtime = mtime;
2213e12c5d1SDavid du Colombier 	}
2223e12c5d1SDavid du Colombier 	d.mode = mode;
223*219b2ee8SDavid du Colombier 	Bflush(b);
2243e12c5d1SDavid du Colombier 	if(dirfwstat(Bfildes(b), &d) < 0)
2253e12c5d1SDavid du Colombier 		warn("can't set modes for %s: %r", name);
2263e12c5d1SDavid du Colombier 	if(uflag){
2273e12c5d1SDavid du Colombier 		if(dirfstat(Bfildes(b), &d) < 0)
2283e12c5d1SDavid du Colombier 			warn("can't reread modes for %s: %r", name);
229*219b2ee8SDavid du Colombier 		if(d.mtime != mtime)
230*219b2ee8SDavid du Colombier 			warn("%s: time mismatch %lud %lud\n", name, mtime, d.mtime);
2313e12c5d1SDavid du Colombier 		if(strcmp(uid, d.uid))
2323e12c5d1SDavid du Colombier 			warn("%s: uid mismatch %s %s", name, uid, d.uid);
2333e12c5d1SDavid du Colombier 		if(strcmp(gid, d.gid))
2343e12c5d1SDavid du Colombier 			warn("%s: gid mismatch %s %s", name, gid, d.gid);
2353e12c5d1SDavid du Colombier 	}
236*219b2ee8SDavid du Colombier 	Bterm(b);
2373e12c5d1SDavid du Colombier }
2383e12c5d1SDavid du Colombier 
2393e12c5d1SDavid du Colombier void
2403e12c5d1SDavid du Colombier seekpast(ulong bytes)
2413e12c5d1SDavid du Colombier {
2423e12c5d1SDavid du Colombier 	char buf[LEN];
2433e12c5d1SDavid du Colombier 	ulong tot, n;
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier 	for(tot = 0; tot < bytes; tot += n){
2463e12c5d1SDavid du Colombier 		n = sizeof buf;
2473e12c5d1SDavid du Colombier 		if(tot + n > bytes)
2483e12c5d1SDavid du Colombier 			n = bytes - tot;
2493e12c5d1SDavid du Colombier 		n = Bread(&bin, buf, n);
2503e12c5d1SDavid du Colombier 		if(n < 0)
2513e12c5d1SDavid du Colombier 			error("premature eof");
2523e12c5d1SDavid du Colombier 	}
2533e12c5d1SDavid du Colombier }
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier void
2563e12c5d1SDavid du Colombier error(char *fmt, ...)
2573e12c5d1SDavid du Colombier {
2583e12c5d1SDavid du Colombier 	char buf[1024];
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier 	sprint(buf, "%s: ", argv0);
2613e12c5d1SDavid du Colombier 	doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1));
2623e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
2633e12c5d1SDavid du Colombier 	exits(0);
2643e12c5d1SDavid du Colombier }
2653e12c5d1SDavid du Colombier 
2663e12c5d1SDavid du Colombier void
2673e12c5d1SDavid du Colombier warn(char *fmt, ...)
2683e12c5d1SDavid du Colombier {
2693e12c5d1SDavid du Colombier 	char buf[1024];
2703e12c5d1SDavid du Colombier 
2713e12c5d1SDavid du Colombier 	sprint(buf, "%s: ", argv0);
2723e12c5d1SDavid du Colombier 	doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1));
2733e12c5d1SDavid du Colombier 	fprint(2, "%s\n", buf);
2743e12c5d1SDavid du Colombier }
2753e12c5d1SDavid du Colombier 
2763e12c5d1SDavid du Colombier void
2773e12c5d1SDavid du Colombier usage(void)
2783e12c5d1SDavid du Colombier {
279*219b2ee8SDavid du Colombier 	fprint(2, "usage: mkext [-h] [-u] [-v] [-d dest-fs] [file ...]\n");
2803e12c5d1SDavid du Colombier }
281