xref: /plan9/sys/src/cmd/fcp.c (revision 16a961bdb6a291dd2ca1e8266b5a1eba656ecc70)
16b811639SDavid du Colombier #include <u.h>
26b811639SDavid du Colombier #include <libc.h>
36b811639SDavid du Colombier #define	DEFB	(8*1024)
46b811639SDavid du Colombier #define	Nwork	16
56b811639SDavid du Colombier 
66b811639SDavid du Colombier int	failed;
76b811639SDavid du Colombier int	gflag;
86b811639SDavid du Colombier int	uflag;
96b811639SDavid du Colombier int	xflag;
106b811639SDavid du Colombier void	copy(char *from, char *to, int todir);
116b811639SDavid du Colombier int	copy1(int fdf, int fdt, char *from, char *to);
126b811639SDavid du Colombier void	worker(int fdf, int fdt, char *from, char *to);
136b811639SDavid du Colombier vlong	nextoff(void);
146b811639SDavid du Colombier void	failure(void *, char *note);
156b811639SDavid du Colombier 
166b811639SDavid du Colombier QLock	lk;
176b811639SDavid du Colombier vlong	off;
186b811639SDavid du Colombier 
196b811639SDavid du Colombier void
main(int argc,char * argv[])206b811639SDavid du Colombier main(int argc, char *argv[])
216b811639SDavid du Colombier {
226b811639SDavid du Colombier 	Dir *dirb;
236b811639SDavid du Colombier 	int todir, i;
246b811639SDavid du Colombier 
256b811639SDavid du Colombier 	ARGBEGIN {
266b811639SDavid du Colombier 	case 'g':
276b811639SDavid du Colombier 		gflag++;
286b811639SDavid du Colombier 		break;
296b811639SDavid du Colombier 	case 'u':
306b811639SDavid du Colombier 		uflag++;
316b811639SDavid du Colombier 		gflag++;
326b811639SDavid du Colombier 		break;
336b811639SDavid du Colombier 	case 'x':
346b811639SDavid du Colombier 		xflag++;
356b811639SDavid du Colombier 		break;
366b811639SDavid du Colombier 	default:
376b811639SDavid du Colombier 		goto usage;
386b811639SDavid du Colombier 	} ARGEND
396b811639SDavid du Colombier 
406b811639SDavid du Colombier 	todir=0;
416b811639SDavid du Colombier 	if(argc < 2)
426b811639SDavid du Colombier 		goto usage;
436b811639SDavid du Colombier 	dirb = dirstat(argv[argc-1]);
446b811639SDavid du Colombier 	if(dirb!=nil && (dirb->mode&DMDIR))
456b811639SDavid du Colombier 		todir=1;
466b811639SDavid du Colombier 	if(argc>2 && !todir){
47*16a961bdSDavid du Colombier 		fprint(2, "fcp: %s not a directory\n", argv[argc-1]);
486b811639SDavid du Colombier 		exits("bad usage");
496b811639SDavid du Colombier 	}
506b811639SDavid du Colombier 	for(i=0; i<argc-1; i++)
516b811639SDavid du Colombier 		copy(argv[i], argv[argc-1], todir);
526b811639SDavid du Colombier 	if(failed)
536b811639SDavid du Colombier 		exits("errors");
546b811639SDavid du Colombier 	exits(0);
556b811639SDavid du Colombier 
566b811639SDavid du Colombier usage:
576b811639SDavid du Colombier 	fprint(2, "usage:\tfcp [-gux] fromfile tofile\n");
586b811639SDavid du Colombier 	fprint(2, "\tfcp [-x] fromfile ... todir\n");
596b811639SDavid du Colombier 	exits("usage");
606b811639SDavid du Colombier }
616b811639SDavid du Colombier 
626b811639SDavid du Colombier int
samefile(Dir * a,char * an,char * bn)636b811639SDavid du Colombier samefile(Dir *a, char *an, char *bn)
646b811639SDavid du Colombier {
656b811639SDavid du Colombier 	Dir *b;
666b811639SDavid du Colombier 	int ret;
676b811639SDavid du Colombier 
686b811639SDavid du Colombier 	ret = 0;
696b811639SDavid du Colombier 	b=dirstat(bn);
706b811639SDavid du Colombier 	if(b != nil)
716b811639SDavid du Colombier 	if(b->qid.type==a->qid.type)
726b811639SDavid du Colombier 	if(b->qid.path==a->qid.path)
736b811639SDavid du Colombier 	if(b->qid.vers==a->qid.vers)
746b811639SDavid du Colombier 	if(b->dev==a->dev)
756b811639SDavid du Colombier 	if(b->type==a->type){
76*16a961bdSDavid du Colombier 		fprint(2, "fcp: %s and %s are the same file\n", an, bn);
776b811639SDavid du Colombier 		ret = 1;
786b811639SDavid du Colombier 	}
796b811639SDavid du Colombier 	free(b);
806b811639SDavid du Colombier 	return ret;
816b811639SDavid du Colombier }
826b811639SDavid du Colombier 
836b811639SDavid du Colombier void
copy(char * from,char * to,int todir)846b811639SDavid du Colombier copy(char *from, char *to, int todir)
856b811639SDavid du Colombier {
866b811639SDavid du Colombier 	Dir *dirb, dirt;
876b811639SDavid du Colombier 	char name[256];
886b811639SDavid du Colombier 	int fdf, fdt, mode;
896b811639SDavid du Colombier 
906b811639SDavid du Colombier 	if(todir){
916b811639SDavid du Colombier 		char *s, *elem;
926b811639SDavid du Colombier 		elem=s=from;
936b811639SDavid du Colombier 		while(*s++)
946b811639SDavid du Colombier 			if(s[-1]=='/')
956b811639SDavid du Colombier 				elem=s;
966b811639SDavid du Colombier 		sprint(name, "%s/%s", to, elem);
976b811639SDavid du Colombier 		to=name;
986b811639SDavid du Colombier 	}
996b811639SDavid du Colombier 
1006b811639SDavid du Colombier 	if((dirb=dirstat(from))==nil){
101*16a961bdSDavid du Colombier 		fprint(2,"fcp: can't stat %s: %r\n", from);
1026b811639SDavid du Colombier 		failed = 1;
1036b811639SDavid du Colombier 		return;
1046b811639SDavid du Colombier 	}
1056b811639SDavid du Colombier 	mode = dirb->mode;
1066b811639SDavid du Colombier 	if(mode&DMDIR){
107*16a961bdSDavid du Colombier 		fprint(2, "fcp: %s is a directory\n", from);
1086b811639SDavid du Colombier 		free(dirb);
1096b811639SDavid du Colombier 		failed = 1;
1106b811639SDavid du Colombier 		return;
1116b811639SDavid du Colombier 	}
1126b811639SDavid du Colombier 	if(samefile(dirb, from, to)){
1136b811639SDavid du Colombier 		free(dirb);
1146b811639SDavid du Colombier 		failed = 1;
1156b811639SDavid du Colombier 		return;
1166b811639SDavid du Colombier 	}
1176b811639SDavid du Colombier 	mode &= 0777;
1186b811639SDavid du Colombier 	fdf=open(from, OREAD);
1196b811639SDavid du Colombier 	if(fdf<0){
120*16a961bdSDavid du Colombier 		fprint(2, "fcp: can't open %s: %r\n", from);
1216b811639SDavid du Colombier 		free(dirb);
1226b811639SDavid du Colombier 		failed = 1;
1236b811639SDavid du Colombier 		return;
1246b811639SDavid du Colombier 	}
1256b811639SDavid du Colombier 	fdt=create(to, OWRITE, mode);
1266b811639SDavid du Colombier 	if(fdt<0){
127*16a961bdSDavid du Colombier 		fprint(2, "fcp: can't create %s: %r\n", to);
1286b811639SDavid du Colombier 		close(fdf);
1296b811639SDavid du Colombier 		free(dirb);
1306b811639SDavid du Colombier 		failed = 1;
1316b811639SDavid du Colombier 		return;
1326b811639SDavid du Colombier 	}
1336b811639SDavid du Colombier 	if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){
1346b811639SDavid du Colombier 		nulldir(&dirt);
1356b811639SDavid du Colombier 		if(xflag){
1366b811639SDavid du Colombier 			dirt.mtime = dirb->mtime;
1376b811639SDavid du Colombier 			dirt.mode = dirb->mode;
1386b811639SDavid du Colombier 		}
1396b811639SDavid du Colombier 		if(uflag)
1406b811639SDavid du Colombier 			dirt.uid = dirb->uid;
1416b811639SDavid du Colombier 		if(gflag)
1426b811639SDavid du Colombier 			dirt.gid = dirb->gid;
1436b811639SDavid du Colombier 		if(dirfwstat(fdt, &dirt) < 0)
144*16a961bdSDavid du Colombier 			fprint(2, "fcp: warning: can't wstat %s: %r\n", to);
1456b811639SDavid du Colombier 	}
1466b811639SDavid du Colombier 	free(dirb);
1476b811639SDavid du Colombier 	close(fdf);
1486b811639SDavid du Colombier 	close(fdt);
1496b811639SDavid du Colombier }
1506b811639SDavid du Colombier 
1516b811639SDavid du Colombier int
copy1(int fdf,int fdt,char * from,char * to)1526b811639SDavid du Colombier copy1(int fdf, int fdt, char *from, char *to)
1536b811639SDavid du Colombier {
1546b811639SDavid du Colombier 	int i, n, rv, pid[Nwork];
1556b811639SDavid du Colombier 	Waitmsg *w;
1566b811639SDavid du Colombier 
1576b811639SDavid du Colombier 	n = 0;
1586b811639SDavid du Colombier 	off = 0;
1596b811639SDavid du Colombier 	for(i=0; i<Nwork; i++){
1606b811639SDavid du Colombier 		switch(pid[n] = rfork(RFPROC|RFMEM)){
1616b811639SDavid du Colombier 		case 0:
1626b811639SDavid du Colombier 			notify(failure);
1636b811639SDavid du Colombier 			worker(fdf, fdt, from, to);
1646b811639SDavid du Colombier 		case -1:
1656b811639SDavid du Colombier 			break;
1666b811639SDavid du Colombier 		default:
1676b811639SDavid du Colombier 			n++;
1686b811639SDavid du Colombier 			break;
1696b811639SDavid du Colombier 		}
1706b811639SDavid du Colombier 	}
1716b811639SDavid du Colombier 	if(n == 0){
172*16a961bdSDavid du Colombier 		fprint(2, "fcp: rfork: %r\n");
1736b811639SDavid du Colombier 		failed = 1;
1746b811639SDavid du Colombier 		return -1;
1756b811639SDavid du Colombier 	}
1766b811639SDavid du Colombier 
1776b811639SDavid du Colombier 	rv = 0;
1786b811639SDavid du Colombier 	while((w = wait()) != nil){
1796b811639SDavid du Colombier 		if(w->msg[0]){
1806b811639SDavid du Colombier 			rv = -1;
1816b811639SDavid du Colombier 			failed = 1;
1826b811639SDavid du Colombier 			for(i=0; i<n; i++)
1836b811639SDavid du Colombier 				if(pid[i] > 0)
1846b811639SDavid du Colombier 					postnote(PNPROC, pid[i], "failure");
1856b811639SDavid du Colombier 		}
1866b811639SDavid du Colombier 		free(w);
1876b811639SDavid du Colombier 	}
1886b811639SDavid du Colombier 	return rv;
1896b811639SDavid du Colombier }
1906b811639SDavid du Colombier 
1916b811639SDavid du Colombier void
worker(int fdf,int fdt,char * from,char * to)1926b811639SDavid du Colombier worker(int fdf, int fdt, char *from, char *to)
1936b811639SDavid du Colombier {
1946b811639SDavid du Colombier 	char buf[DEFB], *bp;
1956b811639SDavid du Colombier 	long len, n;
1966b811639SDavid du Colombier 	vlong o;
1976b811639SDavid du Colombier 
1986b811639SDavid du Colombier 	len = sizeof(buf);
1996b811639SDavid du Colombier 	bp = buf;
2006b811639SDavid du Colombier 	o = nextoff();
2016b811639SDavid du Colombier 
2026b811639SDavid du Colombier 	while(n = pread(fdf, bp, len, o)){
2036b811639SDavid du Colombier 		if(n < 0){
20418027f8cSDavid du Colombier 			fprint(2, "reading %s at %lld: %r\n", from, o);
2056b811639SDavid du Colombier 			_exits("bad");
2066b811639SDavid du Colombier 		}
2076b811639SDavid du Colombier 		if(pwrite(fdt, buf, n, o) != n){
2086b811639SDavid du Colombier 			fprint(2, "writing %s: %r\n", to);
2096b811639SDavid du Colombier 			_exits("bad");
2106b811639SDavid du Colombier 		}
2116b811639SDavid du Colombier 		bp += n;
2126b811639SDavid du Colombier 		o += n;
2136b811639SDavid du Colombier 		len -= n;
2146b811639SDavid du Colombier 		if(len == 0){
2156b811639SDavid du Colombier 			len = sizeof buf;
2166b811639SDavid du Colombier 			bp = buf;
2176b811639SDavid du Colombier 			o = nextoff();
2186b811639SDavid du Colombier 		}
2196b811639SDavid du Colombier 	}
2206b811639SDavid du Colombier 	_exits(nil);
2216b811639SDavid du Colombier }
2226b811639SDavid du Colombier 
2236b811639SDavid du Colombier vlong
nextoff(void)2246b811639SDavid du Colombier nextoff(void)
2256b811639SDavid du Colombier {
2266b811639SDavid du Colombier 	vlong o;
2276b811639SDavid du Colombier 
2286b811639SDavid du Colombier 	qlock(&lk);
2296b811639SDavid du Colombier 	o = off;
2306b811639SDavid du Colombier 	off += DEFB;
2316b811639SDavid du Colombier 	qunlock(&lk);
2326b811639SDavid du Colombier 
2336b811639SDavid du Colombier 	return o;
2346b811639SDavid du Colombier }
2356b811639SDavid du Colombier 
2366b811639SDavid du Colombier void
failure(void *,char * note)2376b811639SDavid du Colombier failure(void*, char *note)
2386b811639SDavid du Colombier {
2396b811639SDavid du Colombier 	if(strcmp(note, "failure") == 0)
2406b811639SDavid du Colombier 		_exits(nil);
2416b811639SDavid du Colombier 	noted(NDFLT);
2426b811639SDavid du Colombier }
243