Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#define	DEFB	(8*1024)
4
#define	Nwork	16
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
void	worker(int fdf, int fdt, char *from, char *to);
13
vlong	nextoff(void);
14
void	failure(void *, char *note);
15
 
16
QLock	lk;
17
vlong	off;
18
 
19
void
20
main(int argc, char *argv[])
21
{
22
	Dir *dirb;
23
	int todir, i;
24
 
25
	ARGBEGIN {
26
	case 'g':
27
		gflag++;
28
		break;
29
	case 'u':
30
		uflag++;
31
		gflag++;
32
		break;
33
	case 'x':
34
		xflag++;
35
		break;
36
	default:
37
		goto usage;
38
	} ARGEND
39
 
40
	todir=0;
41
	if(argc < 2)
42
		goto usage;
43
	dirb = dirstat(argv[argc-1]);
44
	if(dirb!=nil && (dirb->mode&DMDIR))
45
		todir=1;
46
	if(argc>2 && !todir){
47
		fprint(2, "fcp: %s not a directory\n", argv[argc-1]);
48
		exits("bad usage");
49
	}
50
	for(i=0; i<argc-1; i++)
51
		copy(argv[i], argv[argc-1], todir);
52
	if(failed)
53
		exits("errors");
54
	exits(0);
55
 
56
usage:
57
	fprint(2, "usage:\tfcp [-gux] fromfile tofile\n");
58
	fprint(2, "\tfcp [-x] fromfile ... todir\n");
59
	exits("usage");
60
}
61
 
62
int
63
samefile(Dir *a, char *an, char *bn)
64
{
65
	Dir *b;
66
	int ret;
67
 
68
	ret = 0;
69
	b=dirstat(bn);
70
	if(b != nil)
71
	if(b->qid.type==a->qid.type)
72
	if(b->qid.path==a->qid.path)
73
	if(b->qid.vers==a->qid.vers)
74
	if(b->dev==a->dev)
75
	if(b->type==a->type){
76
		fprint(2, "fcp: %s and %s are the same file\n", an, bn);
77
		ret = 1;
78
	}
79
	free(b);
80
	return ret;
81
}
82
 
83
void
84
copy(char *from, char *to, int todir)
85
{
86
	Dir *dirb, dirt;
87
	char name[256];
88
	int fdf, fdt, mode;
89
 
90
	if(todir){
91
		char *s, *elem;
92
		elem=s=from;
93
		while(*s++)
94
			if(s[-1]=='/')
95
				elem=s;
96
		sprint(name, "%s/%s", to, elem);
97
		to=name;
98
	}
99
 
100
	if((dirb=dirstat(from))==nil){
101
		fprint(2,"fcp: can't stat %s: %r\n", from);
102
		failed = 1;
103
		return;
104
	}
105
	mode = dirb->mode;
106
	if(mode&DMDIR){
107
		fprint(2, "fcp: %s is a directory\n", from);
108
		free(dirb);
109
		failed = 1;
110
		return;
111
	}
112
	if(samefile(dirb, from, to)){
113
		free(dirb);
114
		failed = 1;
115
		return;
116
	}
117
	mode &= 0777;
118
	fdf=open(from, OREAD);
119
	if(fdf<0){
120
		fprint(2, "fcp: can't open %s: %r\n", from);
121
		free(dirb);
122
		failed = 1;
123
		return;
124
	}
125
	fdt=create(to, OWRITE, mode);
126
	if(fdt<0){
127
		fprint(2, "fcp: can't create %s: %r\n", to);
128
		close(fdf);
129
		free(dirb);
130
		failed = 1;
131
		return;
132
	}
133
	if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){
134
		nulldir(&dirt);
135
		if(xflag){
136
			dirt.mtime = dirb->mtime;
137
			dirt.mode = dirb->mode;
138
		}
139
		if(uflag)
140
			dirt.uid = dirb->uid;
141
		if(gflag)
142
			dirt.gid = dirb->gid;
143
		if(dirfwstat(fdt, &dirt) < 0)
144
			fprint(2, "fcp: warning: can't wstat %s: %r\n", to);
145
	}			
146
	free(dirb);
147
	close(fdf);
148
	close(fdt);
149
}
150
 
151
int
152
copy1(int fdf, int fdt, char *from, char *to)
153
{
154
	int i, n, rv, pid[Nwork];
155
	Waitmsg *w;
156
 
157
	n = 0;
158
	off = 0;
159
	for(i=0; i<Nwork; i++){
160
		switch(pid[n] = rfork(RFPROC|RFMEM)){
161
		case 0:
162
			notify(failure);
163
			worker(fdf, fdt, from, to);
164
		case -1:
165
			break;
166
		default:
167
			n++;
168
			break;
169
		}
170
	}
171
	if(n == 0){
172
		fprint(2, "fcp: rfork: %r\n");
173
		failed = 1;
174
		return -1;
175
	}
176
 
177
	rv = 0;
178
	while((w = wait()) != nil){
179
		if(w->msg[0]){
180
			rv = -1;
181
			failed = 1;
182
			for(i=0; i<n; i++)
183
				if(pid[i] > 0)
184
					postnote(PNPROC, pid[i], "failure");
185
		}
186
		free(w);
187
	}
188
	return rv;
189
}
190
 
191
void
192
worker(int fdf, int fdt, char *from, char *to)
193
{
194
	char buf[DEFB], *bp;
195
	long len, n;
196
	vlong o;
197
 
198
	len = sizeof(buf);
199
	bp = buf;
200
	o = nextoff();
201
 
202
	while(n = pread(fdf, bp, len, o)){
203
		if(n < 0){
204
			fprint(2, "reading %s at %lld: %r\n", from, o);
205
			_exits("bad");
206
		}
207
		if(pwrite(fdt, buf, n, o) != n){
208
			fprint(2, "writing %s: %r\n", to);
209
			_exits("bad");
210
		}
211
		bp += n;
212
		o += n;
213
		len -= n;
214
		if(len == 0){
215
			len = sizeof buf;
216
			bp = buf;
217
			o = nextoff();
218
		}
219
	}
220
	_exits(nil);
221
}
222
 
223
vlong
224
nextoff(void)
225
{
226
	vlong o;
227
 
228
	qlock(&lk);
229
	o = off;
230
	off += DEFB;
231
	qunlock(&lk);
232
 
233
	return o;
234
}
235
 
236
void
237
failure(void*, char *note)
238
{
239
	if(strcmp(note, "failure") == 0)
240
		_exits(nil);
241
	noted(NDFLT);
242
}