16b811639SDavid du Colombier #include <u.h>
26b811639SDavid du Colombier #include <libc.h>
36b811639SDavid du Colombier #define DEFB (8*1024)
46b811639SDavid du Colombier #define Nwork 16
56b811639SDavid du Colombier
66b811639SDavid du Colombier int failed;
76b811639SDavid du Colombier int gflag;
86b811639SDavid du Colombier int uflag;
96b811639SDavid du Colombier int xflag;
106b811639SDavid du Colombier void copy(char *from, char *to, int todir);
116b811639SDavid du Colombier int copy1(int fdf, int fdt, char *from, char *to);
126b811639SDavid du Colombier void worker(int fdf, int fdt, char *from, char *to);
136b811639SDavid du Colombier vlong nextoff(void);
146b811639SDavid du Colombier void failure(void *, char *note);
156b811639SDavid du Colombier
166b811639SDavid du Colombier QLock lk;
176b811639SDavid du Colombier vlong off;
186b811639SDavid du Colombier
196b811639SDavid du Colombier void
main(int argc,char * argv[])206b811639SDavid du Colombier main(int argc, char *argv[])
216b811639SDavid du Colombier {
226b811639SDavid du Colombier Dir *dirb;
236b811639SDavid du Colombier int todir, i;
246b811639SDavid du Colombier
256b811639SDavid du Colombier ARGBEGIN {
266b811639SDavid du Colombier case 'g':
276b811639SDavid du Colombier gflag++;
286b811639SDavid du Colombier break;
296b811639SDavid du Colombier case 'u':
306b811639SDavid du Colombier uflag++;
316b811639SDavid du Colombier gflag++;
326b811639SDavid du Colombier break;
336b811639SDavid du Colombier case 'x':
346b811639SDavid du Colombier xflag++;
356b811639SDavid du Colombier break;
366b811639SDavid du Colombier default:
376b811639SDavid du Colombier goto usage;
386b811639SDavid du Colombier } ARGEND
396b811639SDavid du Colombier
406b811639SDavid du Colombier todir=0;
416b811639SDavid du Colombier if(argc < 2)
426b811639SDavid du Colombier goto usage;
436b811639SDavid du Colombier dirb = dirstat(argv[argc-1]);
446b811639SDavid du Colombier if(dirb!=nil && (dirb->mode&DMDIR))
456b811639SDavid du Colombier todir=1;
466b811639SDavid du Colombier if(argc>2 && !todir){
47*16a961bdSDavid du Colombier fprint(2, "fcp: %s not a directory\n", argv[argc-1]);
486b811639SDavid du Colombier exits("bad usage");
496b811639SDavid du Colombier }
506b811639SDavid du Colombier for(i=0; i<argc-1; i++)
516b811639SDavid du Colombier copy(argv[i], argv[argc-1], todir);
526b811639SDavid du Colombier if(failed)
536b811639SDavid du Colombier exits("errors");
546b811639SDavid du Colombier exits(0);
556b811639SDavid du Colombier
566b811639SDavid du Colombier usage:
576b811639SDavid du Colombier fprint(2, "usage:\tfcp [-gux] fromfile tofile\n");
586b811639SDavid du Colombier fprint(2, "\tfcp [-x] fromfile ... todir\n");
596b811639SDavid du Colombier exits("usage");
606b811639SDavid du Colombier }
616b811639SDavid du Colombier
626b811639SDavid du Colombier int
samefile(Dir * a,char * an,char * bn)636b811639SDavid du Colombier samefile(Dir *a, char *an, char *bn)
646b811639SDavid du Colombier {
656b811639SDavid du Colombier Dir *b;
666b811639SDavid du Colombier int ret;
676b811639SDavid du Colombier
686b811639SDavid du Colombier ret = 0;
696b811639SDavid du Colombier b=dirstat(bn);
706b811639SDavid du Colombier if(b != nil)
716b811639SDavid du Colombier if(b->qid.type==a->qid.type)
726b811639SDavid du Colombier if(b->qid.path==a->qid.path)
736b811639SDavid du Colombier if(b->qid.vers==a->qid.vers)
746b811639SDavid du Colombier if(b->dev==a->dev)
756b811639SDavid du Colombier if(b->type==a->type){
76*16a961bdSDavid du Colombier fprint(2, "fcp: %s and %s are the same file\n", an, bn);
776b811639SDavid du Colombier ret = 1;
786b811639SDavid du Colombier }
796b811639SDavid du Colombier free(b);
806b811639SDavid du Colombier return ret;
816b811639SDavid du Colombier }
826b811639SDavid du Colombier
836b811639SDavid du Colombier void
copy(char * from,char * to,int todir)846b811639SDavid du Colombier copy(char *from, char *to, int todir)
856b811639SDavid du Colombier {
866b811639SDavid du Colombier Dir *dirb, dirt;
876b811639SDavid du Colombier char name[256];
886b811639SDavid du Colombier int fdf, fdt, mode;
896b811639SDavid du Colombier
906b811639SDavid du Colombier if(todir){
916b811639SDavid du Colombier char *s, *elem;
926b811639SDavid du Colombier elem=s=from;
936b811639SDavid du Colombier while(*s++)
946b811639SDavid du Colombier if(s[-1]=='/')
956b811639SDavid du Colombier elem=s;
966b811639SDavid du Colombier sprint(name, "%s/%s", to, elem);
976b811639SDavid du Colombier to=name;
986b811639SDavid du Colombier }
996b811639SDavid du Colombier
1006b811639SDavid du Colombier if((dirb=dirstat(from))==nil){
101*16a961bdSDavid du Colombier fprint(2,"fcp: can't stat %s: %r\n", from);
1026b811639SDavid du Colombier failed = 1;
1036b811639SDavid du Colombier return;
1046b811639SDavid du Colombier }
1056b811639SDavid du Colombier mode = dirb->mode;
1066b811639SDavid du Colombier if(mode&DMDIR){
107*16a961bdSDavid du Colombier fprint(2, "fcp: %s is a directory\n", from);
1086b811639SDavid du Colombier free(dirb);
1096b811639SDavid du Colombier failed = 1;
1106b811639SDavid du Colombier return;
1116b811639SDavid du Colombier }
1126b811639SDavid du Colombier if(samefile(dirb, from, to)){
1136b811639SDavid du Colombier free(dirb);
1146b811639SDavid du Colombier failed = 1;
1156b811639SDavid du Colombier return;
1166b811639SDavid du Colombier }
1176b811639SDavid du Colombier mode &= 0777;
1186b811639SDavid du Colombier fdf=open(from, OREAD);
1196b811639SDavid du Colombier if(fdf<0){
120*16a961bdSDavid du Colombier fprint(2, "fcp: can't open %s: %r\n", from);
1216b811639SDavid du Colombier free(dirb);
1226b811639SDavid du Colombier failed = 1;
1236b811639SDavid du Colombier return;
1246b811639SDavid du Colombier }
1256b811639SDavid du Colombier fdt=create(to, OWRITE, mode);
1266b811639SDavid du Colombier if(fdt<0){
127*16a961bdSDavid du Colombier fprint(2, "fcp: can't create %s: %r\n", to);
1286b811639SDavid du Colombier close(fdf);
1296b811639SDavid du Colombier free(dirb);
1306b811639SDavid du Colombier failed = 1;
1316b811639SDavid du Colombier return;
1326b811639SDavid du Colombier }
1336b811639SDavid du Colombier if(copy1(fdf, fdt, from, to)==0 && (xflag || gflag || uflag)){
1346b811639SDavid du Colombier nulldir(&dirt);
1356b811639SDavid du Colombier if(xflag){
1366b811639SDavid du Colombier dirt.mtime = dirb->mtime;
1376b811639SDavid du Colombier dirt.mode = dirb->mode;
1386b811639SDavid du Colombier }
1396b811639SDavid du Colombier if(uflag)
1406b811639SDavid du Colombier dirt.uid = dirb->uid;
1416b811639SDavid du Colombier if(gflag)
1426b811639SDavid du Colombier dirt.gid = dirb->gid;
1436b811639SDavid du Colombier if(dirfwstat(fdt, &dirt) < 0)
144*16a961bdSDavid du Colombier fprint(2, "fcp: warning: can't wstat %s: %r\n", to);
1456b811639SDavid du Colombier }
1466b811639SDavid du Colombier free(dirb);
1476b811639SDavid du Colombier close(fdf);
1486b811639SDavid du Colombier close(fdt);
1496b811639SDavid du Colombier }
1506b811639SDavid du Colombier
1516b811639SDavid du Colombier int
copy1(int fdf,int fdt,char * from,char * to)1526b811639SDavid du Colombier copy1(int fdf, int fdt, char *from, char *to)
1536b811639SDavid du Colombier {
1546b811639SDavid du Colombier int i, n, rv, pid[Nwork];
1556b811639SDavid du Colombier Waitmsg *w;
1566b811639SDavid du Colombier
1576b811639SDavid du Colombier n = 0;
1586b811639SDavid du Colombier off = 0;
1596b811639SDavid du Colombier for(i=0; i<Nwork; i++){
1606b811639SDavid du Colombier switch(pid[n] = rfork(RFPROC|RFMEM)){
1616b811639SDavid du Colombier case 0:
1626b811639SDavid du Colombier notify(failure);
1636b811639SDavid du Colombier worker(fdf, fdt, from, to);
1646b811639SDavid du Colombier case -1:
1656b811639SDavid du Colombier break;
1666b811639SDavid du Colombier default:
1676b811639SDavid du Colombier n++;
1686b811639SDavid du Colombier break;
1696b811639SDavid du Colombier }
1706b811639SDavid du Colombier }
1716b811639SDavid du Colombier if(n == 0){
172*16a961bdSDavid du Colombier fprint(2, "fcp: rfork: %r\n");
1736b811639SDavid du Colombier failed = 1;
1746b811639SDavid du Colombier return -1;
1756b811639SDavid du Colombier }
1766b811639SDavid du Colombier
1776b811639SDavid du Colombier rv = 0;
1786b811639SDavid du Colombier while((w = wait()) != nil){
1796b811639SDavid du Colombier if(w->msg[0]){
1806b811639SDavid du Colombier rv = -1;
1816b811639SDavid du Colombier failed = 1;
1826b811639SDavid du Colombier for(i=0; i<n; i++)
1836b811639SDavid du Colombier if(pid[i] > 0)
1846b811639SDavid du Colombier postnote(PNPROC, pid[i], "failure");
1856b811639SDavid du Colombier }
1866b811639SDavid du Colombier free(w);
1876b811639SDavid du Colombier }
1886b811639SDavid du Colombier return rv;
1896b811639SDavid du Colombier }
1906b811639SDavid du Colombier
1916b811639SDavid du Colombier void
worker(int fdf,int fdt,char * from,char * to)1926b811639SDavid du Colombier worker(int fdf, int fdt, char *from, char *to)
1936b811639SDavid du Colombier {
1946b811639SDavid du Colombier char buf[DEFB], *bp;
1956b811639SDavid du Colombier long len, n;
1966b811639SDavid du Colombier vlong o;
1976b811639SDavid du Colombier
1986b811639SDavid du Colombier len = sizeof(buf);
1996b811639SDavid du Colombier bp = buf;
2006b811639SDavid du Colombier o = nextoff();
2016b811639SDavid du Colombier
2026b811639SDavid du Colombier while(n = pread(fdf, bp, len, o)){
2036b811639SDavid du Colombier if(n < 0){
20418027f8cSDavid du Colombier fprint(2, "reading %s at %lld: %r\n", from, o);
2056b811639SDavid du Colombier _exits("bad");
2066b811639SDavid du Colombier }
2076b811639SDavid du Colombier if(pwrite(fdt, buf, n, o) != n){
2086b811639SDavid du Colombier fprint(2, "writing %s: %r\n", to);
2096b811639SDavid du Colombier _exits("bad");
2106b811639SDavid du Colombier }
2116b811639SDavid du Colombier bp += n;
2126b811639SDavid du Colombier o += n;
2136b811639SDavid du Colombier len -= n;
2146b811639SDavid du Colombier if(len == 0){
2156b811639SDavid du Colombier len = sizeof buf;
2166b811639SDavid du Colombier bp = buf;
2176b811639SDavid du Colombier o = nextoff();
2186b811639SDavid du Colombier }
2196b811639SDavid du Colombier }
2206b811639SDavid du Colombier _exits(nil);
2216b811639SDavid du Colombier }
2226b811639SDavid du Colombier
2236b811639SDavid du Colombier vlong
nextoff(void)2246b811639SDavid du Colombier nextoff(void)
2256b811639SDavid du Colombier {
2266b811639SDavid du Colombier vlong o;
2276b811639SDavid du Colombier
2286b811639SDavid du Colombier qlock(&lk);
2296b811639SDavid du Colombier o = off;
2306b811639SDavid du Colombier off += DEFB;
2316b811639SDavid du Colombier qunlock(&lk);
2326b811639SDavid du Colombier
2336b811639SDavid du Colombier return o;
2346b811639SDavid du Colombier }
2356b811639SDavid du Colombier
2366b811639SDavid du Colombier void
failure(void *,char * note)2376b811639SDavid du Colombier failure(void*, char *note)
2386b811639SDavid du Colombier {
2396b811639SDavid du Colombier if(strcmp(note, "failure") == 0)
2406b811639SDavid du Colombier _exits(nil);
2416b811639SDavid du Colombier noted(NDFLT);
2426b811639SDavid du Colombier }
243