vtdump.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. #include "stdinc.h"
  2. #include <bio.h>
  3. typedef struct Source Source;
  4. struct Source
  5. {
  6. ulong gen;
  7. int psize;
  8. int dsize;
  9. int dir;
  10. int active;
  11. int depth;
  12. uvlong size;
  13. uchar score[VtScoreSize];
  14. int reserved;
  15. };
  16. int bsize;
  17. Biobuf *bout;
  18. VtRoot root;
  19. int ver;
  20. int cmp;
  21. int all;
  22. int find;
  23. uchar fscore[VtScoreSize];
  24. VtSession *z;
  25. int vtGetUint16(uchar *p);
  26. ulong vtGetUint32(uchar *p);
  27. uvlong vtGetUint48(uchar *p);
  28. void usage(void);
  29. int parseScore(uchar *score, char *buf, int n);
  30. void readRoot(VtRoot*, uchar *score, char *file);
  31. int dumpDir(Source*, int indent);
  32. void
  33. main(int argc, char *argv[])
  34. {
  35. char *host = nil;
  36. uchar score[VtScoreSize];
  37. Source source;
  38. uchar buf[VtMaxLumpSize];
  39. char *p;
  40. int n;
  41. ARGBEGIN{
  42. case 'h':
  43. host = ARGF();
  44. break;
  45. case 'c':
  46. cmp++;
  47. break;
  48. case 'f':
  49. find++;
  50. p = EARGF(usage());
  51. if(!parseScore(fscore, p, strlen(p)))
  52. usage();
  53. break;
  54. case 'a':
  55. all = 1;
  56. break;
  57. default:
  58. usage();
  59. }ARGEND
  60. vtAttach();
  61. bout = vtMemAllocZ(sizeof(Biobuf));
  62. Binit(bout, 1, OWRITE);
  63. if(argc > 1)
  64. usage();
  65. vtAttach();
  66. fmtinstall('V', vtScoreFmt);
  67. fmtinstall('R', vtErrFmt);
  68. z = vtDial(host, 0);
  69. if(z == nil)
  70. vtFatal("could not connect to server: %s", vtGetError());
  71. if(!vtConnect(z, 0))
  72. sysfatal("vtConnect: %r");
  73. readRoot(&root, score, argv[0]);
  74. ver = root.version;
  75. bsize = root.blockSize;
  76. if(!find) {
  77. Bprint(bout, "score: %V\n", score);
  78. Bprint(bout, "version: %d\n", ver);
  79. Bprint(bout, "name: %s\n", root.name);
  80. Bprint(bout, "type: %s\n", root.type);
  81. Bprint(bout, "bsize: %d\n", bsize);
  82. Bprint(bout, "prev: %V\n", root.prev);
  83. }
  84. if (bsize == 0)
  85. sysfatal("zero bsize");
  86. switch(ver) {
  87. default:
  88. sysfatal("unknown version");
  89. case VtRootVersion:
  90. break;
  91. }
  92. n = vtRead(z, root.score, VtDirType, buf, bsize);
  93. if(n < 0)
  94. sysfatal("could not read root dir");
  95. /* fake up top level source */
  96. memset(&source, 0, sizeof(source));
  97. memmove(source.score, root.score, VtScoreSize);
  98. source.psize = bsize;
  99. source.dsize = bsize;
  100. source.dir = 1;
  101. source.active = 1;
  102. source.depth = 0;
  103. source.size = n;
  104. dumpDir(&source, 0);
  105. Bterm(bout);
  106. vtClose(z);
  107. vtDetach();
  108. exits(0);
  109. }
  110. void
  111. sourcePrint(Source *s, int indent, int entry)
  112. {
  113. int i;
  114. uvlong size;
  115. int ne;
  116. for(i=0; i<indent; i++)
  117. Bprint(bout, " ");
  118. Bprint(bout, "%4d", entry);
  119. if(s->active) {
  120. /* dir size in directory entries */
  121. if(s->dir) {
  122. ne = s->dsize/VtEntrySize;
  123. size = ne*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
  124. } else
  125. size = s->size;
  126. if(cmp) {
  127. Bprint(bout, ": gen: %lud size: %llud",
  128. s->gen, size);
  129. if(!s->dir)
  130. Bprint(bout, ": %V", s->score);
  131. } else {
  132. Bprint(bout, ": gen: %lud psize: %d dsize: %d",
  133. s->gen, s->psize, s->dsize);
  134. Bprint(bout, " depth: %d size: %llud: %V",
  135. s->depth, size, s->score);
  136. }
  137. if(s->reserved)
  138. Bprint(bout, ": reserved not emtpy");
  139. }
  140. Bprint(bout, "\n");
  141. }
  142. int
  143. parse(Source *s, uchar *p)
  144. {
  145. VtEntry dir;
  146. memset(s, 0, sizeof(*s));
  147. if(!vtEntryUnpack(&dir, p, 0))
  148. return 0;
  149. if(!(dir.flags & VtEntryActive))
  150. return 1;
  151. s->active = 1;
  152. s->gen = dir.gen;
  153. s->psize = dir.psize;
  154. s->dsize = dir.size;
  155. s->size = dir.size;
  156. memmove(s->score, dir.score, VtScoreSize);
  157. if(dir.flags & VtEntryDir)
  158. s->dir = 1;
  159. s->depth = dir.depth;
  160. return 1;
  161. }
  162. int
  163. sourceRead(Source *s, ulong block, uchar *p, int n)
  164. {
  165. uchar buf[VtMaxLumpSize];
  166. uchar score[VtScoreSize];
  167. int i, nn, np, type;
  168. int elem[VtPointerDepth];
  169. memmove(score, s->score, VtScoreSize);
  170. np = s->psize/VtScoreSize;
  171. for(i=0; i<s->depth; i++) {
  172. elem[i] = block % np;
  173. block /= np;
  174. }
  175. assert(block == 0);
  176. for(i=s->depth-1; i>=0; i--) {
  177. nn = vtRead(z, score, VtPointerType0+i, buf, s->psize);
  178. if(nn < 0)
  179. return -1;
  180. if(!vtSha1Check(score, buf, nn)) {
  181. vtSetError("vtSha1Check failed on root block");
  182. return -1;
  183. }
  184. if((elem[i]+1)*VtScoreSize > nn)
  185. return 0;
  186. memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
  187. }
  188. if(s->dir)
  189. type = VtDirType;
  190. else
  191. type = VtDataType;
  192. nn = vtRead(z, score, type, p, n);
  193. if(nn < 0)
  194. return -1;
  195. if(!vtSha1Check(score, p, nn)) {
  196. vtSetError("vtSha1Check failed on root block");
  197. return -1;
  198. }
  199. return nn;
  200. }
  201. void
  202. dumpFileContents(Source *s)
  203. {
  204. int nb, lb, i, n;
  205. uchar buf[VtMaxLumpSize];
  206. nb = (s->size + s->dsize - 1)/s->dsize;
  207. lb = s->size%s->dsize;
  208. for(i=0; i<nb; i++) {
  209. memset(buf, 0, s->dsize);
  210. n = sourceRead(s, i, buf, s->dsize);
  211. if(n < 0) {
  212. fprint(2, "could not read block: %d: %s\n", i, vtGetError());
  213. continue;
  214. }
  215. if(i < nb-1)
  216. Bwrite(bout, buf, s->dsize);
  217. else
  218. Bwrite(bout, buf, lb);
  219. }
  220. }
  221. void
  222. dumpFile(Source *s, int indent)
  223. {
  224. int nb, i, j, n;
  225. uchar buf[VtMaxLumpSize];
  226. uchar score[VtScoreSize];
  227. nb = (s->size + s->dsize - 1)/s->dsize;
  228. for(i=0; i<nb; i++) {
  229. memset(buf, 0, s->dsize);
  230. n = sourceRead(s, i, buf, s->dsize);
  231. if(n < 0) {
  232. fprint(2, "could not read block: %d: %s\n", i, vtGetError());
  233. continue;
  234. }
  235. for(j=0; j<indent; j++)
  236. Bprint(bout, " ");
  237. vtSha1(score, buf, n);
  238. Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
  239. }
  240. }
  241. int
  242. dumpDir(Source *s, int indent)
  243. {
  244. int pb, ne, nb, i, j, n, entry;
  245. uchar buf[VtMaxLumpSize];
  246. Source ss;
  247. if (s->dsize == 0)
  248. sysfatal("dumpDir: zero s->dsize");
  249. pb = s->dsize/VtEntrySize;
  250. ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
  251. nb = (s->size + s->dsize - 1)/s->dsize;
  252. for(i=0; i<nb; i++) {
  253. memset(buf, 0, s->dsize);
  254. n = sourceRead(s, i, buf, s->dsize);
  255. if(n < 0) {
  256. fprint(2, "could not read block: %d: %s\n", i, vtGetError());
  257. continue;
  258. }
  259. for(j=0; j<pb; j++) {
  260. entry = i*pb + j;
  261. if(entry >= ne)
  262. break;
  263. parse(&ss, buf + j * VtEntrySize);
  264. if(!find)
  265. sourcePrint(&ss, indent, entry);
  266. else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
  267. dumpFileContents(&ss);
  268. return 0;
  269. }
  270. if(ss.dir) {
  271. if(!dumpDir(&ss, indent+1))
  272. return 0;
  273. } else if(all)
  274. dumpFile(&ss, indent+1);
  275. }
  276. }
  277. return 1;
  278. }
  279. void
  280. usage(void)
  281. {
  282. fprint(2, "usage: %s [-ac] [-f findscore] [-h host] [file]\n", argv0);
  283. exits("usage");
  284. }
  285. int
  286. parseScore(uchar *score, char *buf, int n)
  287. {
  288. int i, c;
  289. memset(score, 0, VtScoreSize);
  290. if(n < VtScoreSize*2)
  291. return 0;
  292. for(i=0; i<VtScoreSize*2; i++) {
  293. if(buf[i] >= '0' && buf[i] <= '9')
  294. c = buf[i] - '0';
  295. else if(buf[i] >= 'a' && buf[i] <= 'f')
  296. c = buf[i] - 'a' + 10;
  297. else if(buf[i] >= 'A' && buf[i] <= 'F')
  298. c = buf[i] - 'A' + 10;
  299. else {
  300. return 0;
  301. }
  302. if((i & 1) == 0)
  303. c <<= 4;
  304. score[i>>1] |= c;
  305. }
  306. return 1;
  307. }
  308. void
  309. readRoot(VtRoot *root, uchar *score, char *file)
  310. {
  311. int fd;
  312. uchar buf[VtRootSize];
  313. int i, n, nn;
  314. if(file == nil)
  315. fd = 0;
  316. else {
  317. fd = open(file, OREAD);
  318. if(fd < 0)
  319. sysfatal("could not open file: %s: %r", file);
  320. }
  321. n = readn(fd, buf, sizeof(buf)-1);
  322. if(n < 0)
  323. sysfatal("read failed: %r");
  324. buf[n] = 0;
  325. close(fd);
  326. for(i=0; i<n; i++) {
  327. if(!parseScore(score, (char*)(buf+i), n-i))
  328. continue;
  329. nn = vtRead(z, score, VtRootType, buf, VtRootSize);
  330. if(nn >= 0) {
  331. if(nn != VtRootSize)
  332. sysfatal("vtRead on root too short");
  333. if(!vtSha1Check(score, buf, VtRootSize))
  334. sysfatal("vtSha1Check failed on root block");
  335. if(!vtRootUnpack(root, buf))
  336. sysfatal("could not parse root: %r");
  337. return;
  338. }
  339. }
  340. sysfatal("could not find root");
  341. }