xref: /plan9/sys/src/cmd/cp.c (revision 5d459b5a09e427ae1acd4e6afcf028853c73946e)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
4219b2ee8SDavid du Colombier #define	DEFB	(8*1024)
53e12c5d1SDavid du Colombier 
6*5d459b5aSDavid du Colombier int	failed;
79a747e4fSDavid du Colombier int	gflag;
89a747e4fSDavid du Colombier int	uflag;
97dd7cddfSDavid du Colombier int	xflag;
103e12c5d1SDavid du Colombier void	copy(char *from, char *to, int todir);
119a747e4fSDavid du Colombier int	copy1(int fdf, int fdt, char *from, char *to);
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier void
main(int argc,char * argv[])143e12c5d1SDavid du Colombier main(int argc, char *argv[])
153e12c5d1SDavid du Colombier {
169a747e4fSDavid du Colombier 	Dir *dirb;
173e12c5d1SDavid du Colombier 	int todir, i;
183e12c5d1SDavid du Colombier 
197dd7cddfSDavid du Colombier 	ARGBEGIN {
209a747e4fSDavid du Colombier 	case 'g':
219a747e4fSDavid du Colombier 		gflag++;
229a747e4fSDavid du Colombier 		break;
239a747e4fSDavid du Colombier 	case 'u':
249a747e4fSDavid du Colombier 		uflag++;
259a747e4fSDavid du Colombier 		gflag++;
269a747e4fSDavid du Colombier 		break;
277dd7cddfSDavid du Colombier 	case 'x':
287dd7cddfSDavid du Colombier 		xflag++;
297dd7cddfSDavid du Colombier 		break;
307dd7cddfSDavid du Colombier 	default:
317dd7cddfSDavid du Colombier 		goto usage;
327dd7cddfSDavid du Colombier 	} ARGEND
337dd7cddfSDavid du Colombier 
343e12c5d1SDavid du Colombier 	todir=0;
357dd7cddfSDavid du Colombier 	if(argc < 2)
367dd7cddfSDavid du Colombier 		goto usage;
379a747e4fSDavid du Colombier 	dirb = dirstat(argv[argc-1]);
389a747e4fSDavid du Colombier 	if(dirb!=nil && (dirb->mode&DMDIR))
393e12c5d1SDavid du Colombier 		todir=1;
407dd7cddfSDavid du Colombier 	if(argc>2 && !todir){
413e12c5d1SDavid du Colombier 		fprint(2, "cp: %s not a directory\n", argv[argc-1]);
423e12c5d1SDavid du Colombier 		exits("bad usage");
433e12c5d1SDavid du Colombier 	}
447dd7cddfSDavid du Colombier 	for(i=0; i<argc-1; i++)
453e12c5d1SDavid du Colombier 		copy(argv[i], argv[argc-1], todir);
46*5d459b5aSDavid du Colombier 	if(failed)
47*5d459b5aSDavid du Colombier 		exits("errors");
483e12c5d1SDavid du Colombier 	exits(0);
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier usage:
519a747e4fSDavid du Colombier 	fprint(2, "usage:\tcp [-gux] fromfile tofile\n");
527dd7cddfSDavid du Colombier 	fprint(2, "\tcp [-x] fromfile ... todir\n");
537dd7cddfSDavid du Colombier 	exits("usage");
543e12c5d1SDavid du Colombier }
553e12c5d1SDavid du Colombier 
569a747e4fSDavid du Colombier int
samefile(Dir * a,char * an,char * bn)579a747e4fSDavid du Colombier samefile(Dir *a, char *an, char *bn)
589a747e4fSDavid du Colombier {
599a747e4fSDavid du Colombier 	Dir *b;
609a747e4fSDavid du Colombier 	int ret;
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier 	ret = 0;
639a747e4fSDavid du Colombier 	b=dirstat(bn);
649a747e4fSDavid du Colombier 	if(b != nil)
659a747e4fSDavid du Colombier 	if(b->qid.type==a->qid.type)
669a747e4fSDavid du Colombier 	if(b->qid.path==a->qid.path)
679a747e4fSDavid du Colombier 	if(b->qid.vers==a->qid.vers)
689a747e4fSDavid du Colombier 	if(b->dev==a->dev)
699a747e4fSDavid du Colombier 	if(b->type==a->type){
709a747e4fSDavid du Colombier 		fprint(2, "cp: %s and %s are the same file\n", an, bn);
719a747e4fSDavid du Colombier 		ret = 1;
729a747e4fSDavid du Colombier 	}
739a747e4fSDavid du Colombier 	free(b);
749a747e4fSDavid du Colombier 	return ret;
759a747e4fSDavid du Colombier }
769a747e4fSDavid du Colombier 
773e12c5d1SDavid du Colombier void
copy(char * from,char * to,int todir)783e12c5d1SDavid du Colombier copy(char *from, char *to, int todir)
793e12c5d1SDavid du Colombier {
809a747e4fSDavid du Colombier 	Dir *dirb, dirt;
813e12c5d1SDavid du Colombier 	char name[256];
829a747e4fSDavid du Colombier 	int fdf, fdt, mode;
833e12c5d1SDavid du Colombier 
843e12c5d1SDavid du Colombier 	if(todir){
853e12c5d1SDavid du Colombier 		char *s, *elem;
863e12c5d1SDavid du Colombier 		elem=s=from;
873e12c5d1SDavid du Colombier 		while(*s++)
883e12c5d1SDavid du Colombier 			if(s[-1]=='/')
893e12c5d1SDavid du Colombier 				elem=s;
903e12c5d1SDavid du Colombier 		sprint(name, "%s/%s", to, elem);
913e12c5d1SDavid du Colombier 		to=name;
923e12c5d1SDavid du Colombier 	}
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier 	if((dirb=dirstat(from))==nil){
95219b2ee8SDavid du Colombier 		fprint(2,"cp: can't stat %s: %r\n", from);
96*5d459b5aSDavid du Colombier 		failed = 1;
973e12c5d1SDavid du Colombier 		return;
983e12c5d1SDavid du Colombier 	}
999a747e4fSDavid du Colombier 	mode = dirb->mode;
1009a747e4fSDavid du Colombier 	if(mode&DMDIR){
1013e12c5d1SDavid du Colombier 		fprint(2, "cp: %s is a directory\n", from);
1029a747e4fSDavid du Colombier 		free(dirb);
103*5d459b5aSDavid du Colombier 		failed = 1;
1043e12c5d1SDavid du Colombier 		return;
1053e12c5d1SDavid du Colombier 	}
1069a747e4fSDavid du Colombier 	if(samefile(dirb, from, to)){
1079a747e4fSDavid du Colombier 		free(dirb);
108*5d459b5aSDavid du Colombier 		failed = 1;
1093e12c5d1SDavid du Colombier 		return;
1103e12c5d1SDavid du Colombier 	}
1119a747e4fSDavid du Colombier 	mode &= 0777;
1123e12c5d1SDavid du Colombier 	fdf=open(from, OREAD);
1133e12c5d1SDavid du Colombier 	if(fdf<0){
114219b2ee8SDavid du Colombier 		fprint(2, "cp: can't open %s: %r\n", from);
1159a747e4fSDavid du Colombier 		free(dirb);
116*5d459b5aSDavid du Colombier 		failed = 1;
1173e12c5d1SDavid du Colombier 		return;
1183e12c5d1SDavid du Colombier 	}
1199a747e4fSDavid du Colombier 	fdt=create(to, OWRITE, mode);
1203e12c5d1SDavid du Colombier 	if(fdt<0){
121219b2ee8SDavid du Colombier 		fprint(2, "cp: can't create %s: %r\n", to);
1223e12c5d1SDavid du Colombier 		close(fdf);
1239a747e4fSDavid du Colombier 		free(dirb);
124*5d459b5aSDavid du Colombier 		failed = 1;
1253e12c5d1SDavid du Colombier 		return;
1263e12c5d1SDavid du Colombier 	}
1279a747e4fSDavid du Colombier 	if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){
1289a747e4fSDavid du Colombier 		nulldir(&dirt);
1299a747e4fSDavid du Colombier 		if(xflag){
1309a747e4fSDavid du Colombier 			dirt.mtime = dirb->mtime;
1319a747e4fSDavid du Colombier 			dirt.mode = dirb->mode;
1329a747e4fSDavid du Colombier 		}
1339a747e4fSDavid du Colombier 		if(uflag)
1349a747e4fSDavid du Colombier 			dirt.uid = dirb->uid;
1359a747e4fSDavid du Colombier 		if(gflag)
1369a747e4fSDavid du Colombier 			dirt.gid = dirb->gid;
1379a747e4fSDavid du Colombier 		if(dirfwstat(fdt, &dirt) < 0)
1389a747e4fSDavid du Colombier 			fprint(2, "cp: warning: can't wstat %s: %r\n", to);
1399a747e4fSDavid du Colombier 	}
1409a747e4fSDavid du Colombier 	free(dirb);
1413e12c5d1SDavid du Colombier 	close(fdf);
1423e12c5d1SDavid du Colombier 	close(fdt);
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier 
1459a747e4fSDavid du Colombier int
copy1(int fdf,int fdt,char * from,char * to)1463e12c5d1SDavid du Colombier copy1(int fdf, int fdt, char *from, char *to)
1473e12c5d1SDavid du Colombier {
148219b2ee8SDavid du Colombier 	char *buf;
149219b2ee8SDavid du Colombier 	long n, n1, rcount;
1509a747e4fSDavid du Colombier 	int rv;
1519a747e4fSDavid du Colombier 	char err[ERRMAX];
1523e12c5d1SDavid du Colombier 
153219b2ee8SDavid du Colombier 	buf = malloc(DEFB);
154219b2ee8SDavid du Colombier 	/* clear any residual error */
1559a747e4fSDavid du Colombier 	err[0] = '\0';
1569a747e4fSDavid du Colombier 	errstr(err, ERRMAX);
1579a747e4fSDavid du Colombier 	rv = 0;
1583e12c5d1SDavid du Colombier 	for(rcount=0;; rcount++) {
159219b2ee8SDavid du Colombier 		n = read(fdf, buf, DEFB);
1603e12c5d1SDavid du Colombier 		if(n <= 0)
1613e12c5d1SDavid du Colombier 			break;
1623e12c5d1SDavid du Colombier 		n1 = write(fdt, buf, n);
1633e12c5d1SDavid du Colombier 		if(n1 != n) {
164219b2ee8SDavid du Colombier 			fprint(2, "cp: error writing %s: %r\n", to);
165*5d459b5aSDavid du Colombier 			failed = 1;
1669a747e4fSDavid du Colombier 			rv = -1;
1673e12c5d1SDavid du Colombier 			break;
1683e12c5d1SDavid du Colombier 		}
1693e12c5d1SDavid du Colombier 	}
1709a747e4fSDavid du Colombier 	if(n < 0) {
171219b2ee8SDavid du Colombier 		fprint(2, "cp: error reading %s: %r\n", from);
172*5d459b5aSDavid du Colombier 		failed = 1;
1739a747e4fSDavid du Colombier 		rv = -1;
1749a747e4fSDavid du Colombier 	}
175219b2ee8SDavid du Colombier 	free(buf);
1769a747e4fSDavid du Colombier 	return rv;
1773e12c5d1SDavid du Colombier }
178