copy.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. #include <venti.h>
  12. #include <libsec.h>
  13. #include <avl.h>
  14. #include <bin.h>
  15. int changes;
  16. int rewrite;
  17. int ignoreerrors;
  18. int fast;
  19. int verbose;
  20. int nskip;
  21. int nwrite;
  22. VtConn *zsrc, *zdst;
  23. uint8_t zeroscore[VtScoreSize]; /* all zeros */
  24. typedef struct ScoreTree ScoreTree;
  25. struct ScoreTree
  26. {
  27. Avl avl;
  28. uint8_t score[VtScoreSize];
  29. int type;
  30. };
  31. Avltree *scoretree;
  32. Bin *scorebin;
  33. static int
  34. scoretreecmp(Avl *va, Avl *vb)
  35. {
  36. ScoreTree *a, *b;
  37. int i;
  38. a = (ScoreTree*)va;
  39. b = (ScoreTree*)vb;
  40. i = memcmp(a->score, b->score, VtScoreSize);
  41. if(i != 0)
  42. return i;
  43. return a->type - b->type;
  44. }
  45. static int
  46. havevisited(uint8_t score[VtScoreSize], int type)
  47. {
  48. ScoreTree a;
  49. if(scoretree == nil)
  50. return 0;
  51. memmove(a.score, score, VtScoreSize);
  52. a.type = type;
  53. return lookupavl(scoretree, &a.avl) != nil;
  54. }
  55. static void
  56. markvisited(uint8_t score[VtScoreSize], int type)
  57. {
  58. ScoreTree *a;
  59. Avl *old;
  60. if(scoretree == nil)
  61. return;
  62. a = binalloc(&scorebin, sizeof *a, 1);
  63. memmove(a->score, score, VtScoreSize);
  64. a->type = type;
  65. insertavl(scoretree, &a->avl, &old);
  66. }
  67. void
  68. usage(void)
  69. {
  70. fprint(2, "usage: %s [-fimrv] [-t type] srchost dsthost score\n", argv0);
  71. exits("usage");
  72. }
  73. void
  74. walk(uint8_t score[VtScoreSize], uint type, int base)
  75. {
  76. int i, n;
  77. uint8_t *buf;
  78. uint8_t nscore[VtScoreSize];
  79. VtEntry e;
  80. VtRoot root;
  81. if(memcmp(score, vtzeroscore, VtScoreSize) == 0 || memcmp(score, zeroscore, VtScoreSize) == 0)
  82. return;
  83. if(havevisited(score, type)){
  84. nskip++;
  85. return;
  86. }
  87. buf = vtmallocz(VtMaxLumpSize);
  88. if(fast && vtread(zdst, score, type, buf, VtMaxLumpSize) >= 0){
  89. if(verbose)
  90. fprint(2, "skip %V\n", score);
  91. free(buf);
  92. return;
  93. }
  94. n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
  95. if(n < 0){
  96. if(rewrite){
  97. changes++;
  98. memmove(score, vtzeroscore, VtScoreSize);
  99. }else if(!ignoreerrors)
  100. sysfatal("reading block %V (type %d): %r", score, type);
  101. return;
  102. }
  103. switch(type){
  104. case VtRootType:
  105. if(vtrootunpack(&root, buf) < 0){
  106. fprint(2, "warning: could not unpack root in %V %d\n", score, type);
  107. break;
  108. }
  109. walk(root.prev, VtRootType, 0);
  110. walk(root.score, VtDirType, 0);
  111. if(rewrite)
  112. vtrootpack(&root, buf); /* walk might have changed score */
  113. break;
  114. case VtDirType:
  115. for(i=0; i*VtEntrySize<n; i++){
  116. if(vtentryunpack(&e, buf, i) < 0){
  117. fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
  118. continue;
  119. }
  120. if(!(e.flags & VtEntryActive))
  121. continue;
  122. walk(e.score, e.type, e.type&VtTypeBaseMask);
  123. /*
  124. * Don't repack unless we're rewriting -- some old
  125. * vac files have psize==0 and dsize==0, and these
  126. * get rewritten by vtentryunpack to have less strange
  127. * block sizes. So vtentryunpack; vtentrypack does not
  128. * guarantee to preserve the exact bytes in buf.
  129. */
  130. if(rewrite)
  131. vtentrypack(&e, buf, i);
  132. }
  133. break;
  134. case VtDataType:
  135. break;
  136. default: /* pointers */
  137. for(i=0; i<n; i+=VtScoreSize)
  138. if(memcmp(buf+i, vtzeroscore, VtScoreSize) != 0)
  139. walk(buf+i, type-1, base);
  140. break;
  141. }
  142. nwrite++;
  143. if(vtwrite(zdst, nscore, type, buf, n) < 0){
  144. /* figure out score for better error message */
  145. /* can't use input argument - might have changed contents */
  146. n = vtzerotruncate(type, buf, n);
  147. sha1(buf, n, score, nil);
  148. sysfatal("writing block %V (type %d): %r", score, type);
  149. }
  150. if(!rewrite && memcmp(score, nscore, VtScoreSize) != 0){
  151. fprint(2, "not rewriting: wrote %V got %V\n", score, nscore);
  152. abort();
  153. sysfatal("not rewriting: wrote %V got %V", score, nscore);
  154. }
  155. markvisited(score, type);
  156. free(buf);
  157. }
  158. void
  159. main(int argc, char *argv[])
  160. {
  161. int type, n;
  162. uchar score[VtScoreSize];
  163. uchar *buf;
  164. char *prefix;
  165. fmtinstall('F', vtfcallfmt);
  166. fmtinstall('V', vtscorefmt);
  167. type = -1;
  168. ARGBEGIN{
  169. case 'V':
  170. chattyventi++;
  171. break;
  172. case 'f':
  173. fast = 1;
  174. break;
  175. case 'i':
  176. if(rewrite)
  177. usage();
  178. ignoreerrors = 1;
  179. break;
  180. case 'm':
  181. scoretree = mkavltree(scoretreecmp);
  182. break;
  183. case 'r':
  184. if(ignoreerrors)
  185. usage();
  186. rewrite = 1;
  187. break;
  188. case 't':
  189. type = atoi(EARGF(usage()));
  190. break;
  191. case 'v':
  192. verbose = 1;
  193. break;
  194. default:
  195. usage();
  196. break;
  197. }ARGEND
  198. if(argc != 3)
  199. usage();
  200. if(vtparsescore(argv[2], &prefix, score) < 0)
  201. sysfatal("could not parse score: %r");
  202. buf = vtmallocz(VtMaxLumpSize);
  203. zsrc = vtdial(argv[0]);
  204. if(zsrc == nil)
  205. sysfatal("could not dial src server: %r");
  206. if(vtconnect(zsrc) < 0)
  207. sysfatal("vtconnect src: %r");
  208. zdst = vtdial(argv[1]);
  209. if(zdst == nil)
  210. sysfatal("could not dial dst server: %r");
  211. if(vtconnect(zdst) < 0)
  212. sysfatal("vtconnect dst: %r");
  213. if(type != -1){
  214. n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
  215. if(n < 0)
  216. sysfatal("could not read block: %r");
  217. }else{
  218. for(type=0; type<VtMaxType; type++){
  219. n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
  220. if(n >= 0)
  221. break;
  222. }
  223. if(type == VtMaxType)
  224. sysfatal("could not find block %V of any type", score);
  225. }
  226. walk(score, type, VtDirType);
  227. if(changes)
  228. print("%s:%V (%d pointers rewritten)\n", prefix, score, changes);
  229. if(verbose)
  230. print("%d skipped, %d written\n", nskip, nwrite);
  231. if(vtsync(zdst) < 0)
  232. sysfatal("could not sync dst server: %r");
  233. exits(0);
  234. }