fcp.c 4.1 KB

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