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