xref: /plan9/sys/src/cmd/cp.c (revision 5d459b5a09e427ae1acd4e6afcf028853c73946e)
1 #include <u.h>
2 #include <libc.h>
3 
4 #define	DEFB	(8*1024)
5 
6 int	failed;
7 int	gflag;
8 int	uflag;
9 int	xflag;
10 void	copy(char *from, char *to, int todir);
11 int	copy1(int fdf, int fdt, char *from, char *to);
12 
13 void
main(int argc,char * argv[])14 main(int argc, char *argv[])
15 {
16 	Dir *dirb;
17 	int todir, i;
18 
19 	ARGBEGIN {
20 	case 'g':
21 		gflag++;
22 		break;
23 	case 'u':
24 		uflag++;
25 		gflag++;
26 		break;
27 	case 'x':
28 		xflag++;
29 		break;
30 	default:
31 		goto usage;
32 	} ARGEND
33 
34 	todir=0;
35 	if(argc < 2)
36 		goto usage;
37 	dirb = dirstat(argv[argc-1]);
38 	if(dirb!=nil && (dirb->mode&DMDIR))
39 		todir=1;
40 	if(argc>2 && !todir){
41 		fprint(2, "cp: %s not a directory\n", argv[argc-1]);
42 		exits("bad usage");
43 	}
44 	for(i=0; i<argc-1; i++)
45 		copy(argv[i], argv[argc-1], todir);
46 	if(failed)
47 		exits("errors");
48 	exits(0);
49 
50 usage:
51 	fprint(2, "usage:\tcp [-gux] fromfile tofile\n");
52 	fprint(2, "\tcp [-x] fromfile ... todir\n");
53 	exits("usage");
54 }
55 
56 int
samefile(Dir * a,char * an,char * bn)57 samefile(Dir *a, char *an, char *bn)
58 {
59 	Dir *b;
60 	int ret;
61 
62 	ret = 0;
63 	b=dirstat(bn);
64 	if(b != nil)
65 	if(b->qid.type==a->qid.type)
66 	if(b->qid.path==a->qid.path)
67 	if(b->qid.vers==a->qid.vers)
68 	if(b->dev==a->dev)
69 	if(b->type==a->type){
70 		fprint(2, "cp: %s and %s are the same file\n", an, bn);
71 		ret = 1;
72 	}
73 	free(b);
74 	return ret;
75 }
76 
77 void
copy(char * from,char * to,int todir)78 copy(char *from, char *to, int todir)
79 {
80 	Dir *dirb, dirt;
81 	char name[256];
82 	int fdf, fdt, mode;
83 
84 	if(todir){
85 		char *s, *elem;
86 		elem=s=from;
87 		while(*s++)
88 			if(s[-1]=='/')
89 				elem=s;
90 		sprint(name, "%s/%s", to, elem);
91 		to=name;
92 	}
93 
94 	if((dirb=dirstat(from))==nil){
95 		fprint(2,"cp: can't stat %s: %r\n", from);
96 		failed = 1;
97 		return;
98 	}
99 	mode = dirb->mode;
100 	if(mode&DMDIR){
101 		fprint(2, "cp: %s is a directory\n", from);
102 		free(dirb);
103 		failed = 1;
104 		return;
105 	}
106 	if(samefile(dirb, from, to)){
107 		free(dirb);
108 		failed = 1;
109 		return;
110 	}
111 	mode &= 0777;
112 	fdf=open(from, OREAD);
113 	if(fdf<0){
114 		fprint(2, "cp: can't open %s: %r\n", from);
115 		free(dirb);
116 		failed = 1;
117 		return;
118 	}
119 	fdt=create(to, OWRITE, mode);
120 	if(fdt<0){
121 		fprint(2, "cp: can't create %s: %r\n", to);
122 		close(fdf);
123 		free(dirb);
124 		failed = 1;
125 		return;
126 	}
127 	if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){
128 		nulldir(&dirt);
129 		if(xflag){
130 			dirt.mtime = dirb->mtime;
131 			dirt.mode = dirb->mode;
132 		}
133 		if(uflag)
134 			dirt.uid = dirb->uid;
135 		if(gflag)
136 			dirt.gid = dirb->gid;
137 		if(dirfwstat(fdt, &dirt) < 0)
138 			fprint(2, "cp: warning: can't wstat %s: %r\n", to);
139 	}
140 	free(dirb);
141 	close(fdf);
142 	close(fdt);
143 }
144 
145 int
copy1(int fdf,int fdt,char * from,char * to)146 copy1(int fdf, int fdt, char *from, char *to)
147 {
148 	char *buf;
149 	long n, n1, rcount;
150 	int rv;
151 	char err[ERRMAX];
152 
153 	buf = malloc(DEFB);
154 	/* clear any residual error */
155 	err[0] = '\0';
156 	errstr(err, ERRMAX);
157 	rv = 0;
158 	for(rcount=0;; rcount++) {
159 		n = read(fdf, buf, DEFB);
160 		if(n <= 0)
161 			break;
162 		n1 = write(fdt, buf, n);
163 		if(n1 != n) {
164 			fprint(2, "cp: error writing %s: %r\n", to);
165 			failed = 1;
166 			rv = -1;
167 			break;
168 		}
169 	}
170 	if(n < 0) {
171 		fprint(2, "cp: error reading %s: %r\n", from);
172 		failed = 1;
173 		rv = -1;
174 	}
175 	free(buf);
176 	return rv;
177 }
178