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 } 243