copy.c 5.1 KB

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