vtdump.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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, dsize;
  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. dsize = s->dsize;
  123. if (dsize <= 0) {
  124. fprint(2, "%s: non-positive dsize %d in dir %V\n",
  125. argv0, s->dsize, s->score);
  126. dsize = 1; /* don't divide by zero */
  127. }
  128. ne = s->dsize/VtEntrySize;
  129. size = ne*(s->size/dsize) +
  130. (s->size%dsize)/VtEntrySize;
  131. } else
  132. size = s->size;
  133. if(cmp) {
  134. Bprint(bout, ": gen: %lud size: %llud",
  135. s->gen, size);
  136. if(!s->dir)
  137. Bprint(bout, ": %V", s->score);
  138. } else {
  139. Bprint(bout, ": gen: %lud psize: %d dsize: %d",
  140. s->gen, s->psize, s->dsize);
  141. Bprint(bout, " depth: %d size: %llud: %V",
  142. s->depth, size, s->score);
  143. }
  144. if(s->reserved)
  145. Bprint(bout, ": reserved not emtpy");
  146. }
  147. Bprint(bout, "\n");
  148. }
  149. int
  150. parse(Source *s, uchar *p)
  151. {
  152. VtEntry dir;
  153. memset(s, 0, sizeof(*s));
  154. if(!vtEntryUnpack(&dir, p, 0))
  155. return 0;
  156. if(!(dir.flags & VtEntryActive))
  157. return 1;
  158. s->active = 1;
  159. s->gen = dir.gen;
  160. s->psize = dir.psize;
  161. s->dsize = dir.dsize;
  162. s->size = dir.size;
  163. memmove(s->score, dir.score, VtScoreSize);
  164. if(dir.flags & VtEntryDir)
  165. s->dir = 1;
  166. s->depth = dir.depth;
  167. return 1;
  168. }
  169. int
  170. sourceRead(Source *s, ulong block, uchar *p, int n)
  171. {
  172. uchar buf[VtMaxLumpSize];
  173. uchar score[VtScoreSize];
  174. int i, nn, np, type;
  175. int elem[VtPointerDepth];
  176. memmove(score, s->score, VtScoreSize);
  177. np = s->psize/VtScoreSize;
  178. assert(np > 0);
  179. for(i=0; i<s->depth; i++) {
  180. elem[i] = block % np;
  181. block /= np;
  182. }
  183. assert(block == 0);
  184. for(i=s->depth-1; i>=0; i--) {
  185. nn = vtRead(z, score, VtPointerType0+i, buf, s->psize);
  186. if(nn < 0)
  187. return -1;
  188. if(!vtSha1Check(score, buf, nn)) {
  189. vtSetError("vtSha1Check failed on root block");
  190. return -1;
  191. }
  192. if((elem[i]+1)*VtScoreSize > nn)
  193. return 0;
  194. memmove(score, buf + elem[i]*VtScoreSize, VtScoreSize);
  195. }
  196. if(s->dir)
  197. type = VtDirType;
  198. else
  199. type = VtDataType;
  200. nn = vtRead(z, score, type, p, n);
  201. if(nn < 0)
  202. return -1;
  203. if(!vtSha1Check(score, p, nn)) {
  204. vtSetError("vtSha1Check failed on root block");
  205. return -1;
  206. }
  207. return nn;
  208. }
  209. void
  210. dumpFileContents(Source *s)
  211. {
  212. int nb, lb, i, n;
  213. uchar buf[VtMaxLumpSize];
  214. nb = (s->size + s->dsize - 1)/s->dsize;
  215. lb = s->size%s->dsize;
  216. for(i=0; i<nb; i++) {
  217. if (s->dsize > sizeof buf) {
  218. fprint(2, "%s: implausibly large s->dsize %d for %V\n",
  219. argv0, s->dsize, s->score);
  220. continue;
  221. }
  222. memset(buf, 0, s->dsize);
  223. n = sourceRead(s, i, buf, s->dsize);
  224. if(n < 0) {
  225. fprint(2, "could not read block: %d: %s\n", i, vtGetError());
  226. continue;
  227. }
  228. if(i < nb-1)
  229. Bwrite(bout, buf, s->dsize);
  230. else
  231. Bwrite(bout, buf, lb);
  232. }
  233. }
  234. void
  235. dumpFile(Source *s, int indent)
  236. {
  237. int nb, i, j, n;
  238. uchar buf[VtMaxLumpSize];
  239. uchar score[VtScoreSize];
  240. nb = (s->size + s->dsize - 1)/s->dsize;
  241. for(i=0; i<nb; i++) {
  242. if (s->dsize > sizeof buf) {
  243. fprint(2, "%s: implausibly large s->dsize %d for %V\n",
  244. argv0, s->dsize, s->score);
  245. continue;
  246. }
  247. memset(buf, 0, s->dsize);
  248. n = sourceRead(s, i, buf, s->dsize);
  249. if(n < 0) {
  250. fprint(2, "could not read block: %d: %s\n", i, vtGetError());
  251. continue;
  252. }
  253. for(j=0; j<indent; j++)
  254. Bprint(bout, " ");
  255. vtSha1(score, buf, n);
  256. Bprint(bout, "%4d: size: %ud: %V\n", i, n, score);
  257. }
  258. }
  259. int
  260. dumpDir(Source *s, int indent)
  261. {
  262. int pb, ne, nb, i, j, n, entry;
  263. uchar buf[VtMaxLumpSize];
  264. Source ss;
  265. if (s->dsize <= 0) {
  266. fprint(2, "%s: dumpDir %V: non-positive s->dsize %d\n",
  267. argv0, s->score, s->dsize);
  268. return 1;
  269. }
  270. pb = s->dsize/VtEntrySize;
  271. ne = pb*(s->size/s->dsize) + (s->size%s->dsize)/VtEntrySize;
  272. nb = (s->size + s->dsize - 1)/s->dsize;
  273. for(i=0; i<nb; i++) {
  274. if (s->dsize > sizeof buf) {
  275. fprint(2, "%s: implausibly large s->dsize %d for %V\n",
  276. argv0, s->dsize, s->score);
  277. continue;
  278. }
  279. memset(buf, 0, s->dsize);
  280. n = sourceRead(s, i, buf, s->dsize);
  281. if(n < 0) {
  282. fprint(2, "could not read block: %d: %s\n", i, vtGetError());
  283. continue;
  284. }
  285. for(j=0; j<pb; j++) {
  286. entry = i*pb + j;
  287. if(entry >= ne)
  288. break;
  289. parse(&ss, buf + j * VtEntrySize);
  290. if(!find)
  291. sourcePrint(&ss, indent, entry);
  292. else if(memcmp(ss.score, fscore, VtScoreSize) == 0) {
  293. dumpFileContents(&ss);
  294. return 0;
  295. }
  296. if(ss.dir) {
  297. if(!dumpDir(&ss, indent+1))
  298. return 0;
  299. } else if(all)
  300. dumpFile(&ss, indent+1);
  301. }
  302. }
  303. return 1;
  304. }
  305. void
  306. usage(void)
  307. {
  308. fprint(2, "usage: %s [-ac] [-f findscore] [-h host] [file]\n", argv0);
  309. exits("usage");
  310. }
  311. int
  312. parseScore(uchar *score, char *buf, int n)
  313. {
  314. int i, c;
  315. memset(score, 0, VtScoreSize);
  316. if(n < VtScoreSize*2)
  317. return 0;
  318. for(i=0; i<VtScoreSize*2; i++) {
  319. if(buf[i] >= '0' && buf[i] <= '9')
  320. c = buf[i] - '0';
  321. else if(buf[i] >= 'a' && buf[i] <= 'f')
  322. c = buf[i] - 'a' + 10;
  323. else if(buf[i] >= 'A' && buf[i] <= 'F')
  324. c = buf[i] - 'A' + 10;
  325. else {
  326. return 0;
  327. }
  328. if((i & 1) == 0)
  329. c <<= 4;
  330. score[i>>1] |= c;
  331. }
  332. return 1;
  333. }
  334. void
  335. readRoot(VtRoot *root, uchar *score, char *file)
  336. {
  337. int fd;
  338. uchar buf[VtRootSize];
  339. int i, n, nn;
  340. if(file == nil)
  341. fd = 0;
  342. else {
  343. fd = open(file, OREAD);
  344. if(fd < 0)
  345. sysfatal("could not open file: %s: %r", file);
  346. }
  347. n = readn(fd, buf, sizeof(buf)-1);
  348. if(n < 0)
  349. sysfatal("read failed: %r");
  350. buf[n] = 0;
  351. close(fd);
  352. for(i=0; i<n; i++) {
  353. if(!parseScore(score, (char*)(buf+i), n-i))
  354. continue;
  355. nn = vtRead(z, score, VtRootType, buf, VtRootSize);
  356. if(nn >= 0) {
  357. if(nn != VtRootSize)
  358. sysfatal("vtRead on root too short");
  359. if(!vtSha1Check(score, buf, VtRootSize))
  360. sysfatal("vtSha1Check failed on root block");
  361. if(!vtRootUnpack(root, buf))
  362. sysfatal("could not parse root: %r");
  363. return;
  364. }
  365. }
  366. sysfatal("could not find root");
  367. }