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
main(int argc,char * argv[])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
samefile(Dir * a,char * an,char * bn)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
copy(char * from,char * to,int todir)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
copy1(int fdf,int fdt,char * from,char * to)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
worker(int fdf,int fdt,char * from,char * to)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
nextoff(void)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
failure(void *,char * note)237 failure(void*, char *note)
238 {
239 if(strcmp(note, "failure") == 0)
240 _exits(nil);
241 noted(NDFLT);
242 }
243