vtdump.c 7.0 KB

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