copy.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. static int fast;
  5. static int quiet;
  6. VtSession *zsrc, *zdst;
  7. void
  8. usage(void)
  9. {
  10. fprint(2, "usage: copy [-fq] src-host dst-host score [type]\n");
  11. exits("usage");
  12. }
  13. int
  14. parseScore(uchar *score, char *buf, int n)
  15. {
  16. int i, c;
  17. memset(score, 0, VtScoreSize);
  18. if(n < VtScoreSize*2)
  19. return 0;
  20. for(i=0; i<VtScoreSize*2; i++) {
  21. if(buf[i] >= '0' && buf[i] <= '9')
  22. c = buf[i] - '0';
  23. else if(buf[i] >= 'a' && buf[i] <= 'f')
  24. c = buf[i] - 'a' + 10;
  25. else if(buf[i] >= 'A' && buf[i] <= 'F')
  26. c = buf[i] - 'A' + 10;
  27. else {
  28. return 0;
  29. }
  30. if((i & 1) == 0)
  31. c <<= 4;
  32. score[i>>1] |= c;
  33. }
  34. return 1;
  35. }
  36. void
  37. walk(uchar score[VtScoreSize], uint type, int base)
  38. {
  39. int i, n, sub;
  40. uchar *buf;
  41. VtEntry e;
  42. VtRoot root;
  43. if(memcmp(score, vtZeroScore, VtScoreSize) == 0)
  44. return;
  45. buf = vtMemAllocZ(VtMaxLumpSize);
  46. if(fast && vtRead(zdst, score, type, buf, VtMaxLumpSize) >= 0){
  47. if(!quiet)
  48. fprint(2, "%V already exists on dst server; skipping.\n", score);
  49. free(buf);
  50. return;
  51. }
  52. n = vtRead(zsrc, score, type, buf, VtMaxLumpSize);
  53. /*
  54. * we usually see this at the end of a venti/copy of a vac tree:
  55. * warning: could not read block \
  56. * 0000000000000000000000000000000000000000 1: \
  57. * no block with that score exists
  58. * maybe it's harmless.
  59. */
  60. if(n < 0){
  61. fprint(2, "warning: could not read block %V %d: %R\n",
  62. score, type);
  63. return;
  64. }
  65. switch(type){
  66. case VtRootType:
  67. if(!vtRootUnpack(&root, buf)){
  68. fprint(2, "warning: could not unpack root in %V %d\n", score, type);
  69. break;
  70. }
  71. walk(root.score, VtDirType, 0);
  72. walk(root.prev, VtRootType, 0);
  73. break;
  74. case VtDirType:
  75. for(i=0; i<n/VtEntrySize; i++){
  76. if(!vtEntryUnpack(&e, buf, i)){
  77. fprint(2, "warning: could not unpack entry #%d in %V %d\n", i, score, type);
  78. continue;
  79. }
  80. if(!(e.flags & VtEntryActive))
  81. continue;
  82. if(e.flags&VtEntryDir)
  83. base = VtDirType;
  84. else
  85. base = VtDataType;
  86. if(e.depth == 0)
  87. sub = base;
  88. else
  89. sub = VtPointerType0+e.depth-1;
  90. walk(e.score, sub, base);
  91. }
  92. break;
  93. case VtDataType:
  94. break;
  95. default: /* pointers */
  96. if(type == VtPointerType0)
  97. sub = base;
  98. else
  99. sub = type-1;
  100. for(i=0; i<n; i+=VtScoreSize)
  101. if(memcmp(buf+i, vtZeroScore, VtScoreSize) != 0)
  102. walk(buf+i, sub, base);
  103. break;
  104. }
  105. if(!vtWrite(zdst, score, type, buf, n))
  106. fprint(2, "warning: could not write block %V %d: %R\n", score, type);
  107. free(buf);
  108. }
  109. void
  110. main(int argc, char *argv[])
  111. {
  112. int type, n;
  113. uchar score[VtScoreSize];
  114. uchar *buf;
  115. ARGBEGIN{
  116. case 'f':
  117. fast = 1;
  118. break;
  119. case 'q':
  120. quiet = 1;
  121. break;
  122. default:
  123. usage();
  124. break;
  125. }ARGEND
  126. if(argc != 3 && argc != 4)
  127. usage();
  128. vtAttach();
  129. fmtinstall('V', vtScoreFmt);
  130. fmtinstall('R', vtErrFmt);
  131. if(!parseScore(score, argv[2], strlen(argv[2])))
  132. vtFatal("could not parse score: %s", vtGetError());
  133. buf = vtMemAllocZ(VtMaxLumpSize);
  134. zsrc = vtDial(argv[0], 0);
  135. if(zsrc == nil)
  136. vtFatal("could not dial src server: %R");
  137. if(!vtConnect(zsrc, 0))
  138. sysfatal("vtConnect src: %r");
  139. zdst = vtDial(argv[1], 0);
  140. if(zdst == nil)
  141. vtFatal("could not dial dst server: %R");
  142. if(!vtConnect(zdst, 0))
  143. sysfatal("vtConnect dst: %r");
  144. if(argc == 4){
  145. type = atoi(argv[3]);
  146. n = vtRead(zsrc, score, type, buf, VtMaxLumpSize);
  147. if(n < 0)
  148. vtFatal("could not read block: %R");
  149. }else{
  150. for(type=0; type<VtMaxType; type++){
  151. n = vtRead(zsrc, score, type, buf, VtMaxLumpSize);
  152. if(n >= 0)
  153. break;
  154. }
  155. if(type == VtMaxType)
  156. vtFatal("could not find block %V of any type", score);
  157. }
  158. walk(score, type, VtDirType);
  159. if(!vtSync(zdst))
  160. vtFatal("could not sync dst server: %R");
  161. vtDetach();
  162. exits(0);
  163. }