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