vac.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. #include "stdinc.h"
  2. #include "vac.h"
  3. #include "dat.h"
  4. #include "fns.h"
  5. typedef struct Sink Sink;
  6. typedef struct MetaSink MetaSink;
  7. typedef struct DirSink DirSink;
  8. struct Sink {
  9. VtSession *z;
  10. VtEntry dir;
  11. uchar *buf;
  12. uchar *pbuf[VtPointerDepth+1];
  13. };
  14. struct DirSink {
  15. Sink *sink;
  16. MetaSink *msink;
  17. ulong nentry;
  18. uchar *buf;
  19. uchar *p; /* current pointer */
  20. uchar *ep; /* end pointer */
  21. };
  22. struct MetaSink {
  23. Sink *sink;
  24. uchar *buf;
  25. int maxindex;
  26. int nindex;
  27. uchar *rp; /* start of current record */
  28. uchar *p; /* current pointer */
  29. uchar *ep; /* end pointer */
  30. };
  31. static void usage(void);
  32. static int strpCmp(void*, void*);
  33. static void warn(char *fmt, ...);
  34. static void cleanup(void);
  35. static u64int unittoull(char *s);
  36. static int vac(VtSession *z, char *argv[]);
  37. static void vacFile(DirSink *dsink, char *lname, char *sname, VacFile*);
  38. static void vacStdin(DirSink *dsink, char *name, VacFile *vf);
  39. static void vacData(DirSink *dsink, int fd, char *lname, VacFile*, Dir*);
  40. static void vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile*);
  41. static int vacMerge(DirSink *dsink, char *lname, char *sname);
  42. Sink *sinkAlloc(VtSession *z, int psize, int dsize);
  43. void sinkWrite(Sink *k, uchar *data, int n);
  44. void sinkWriteScore(Sink *k, uchar *score, int n);
  45. void sinkClose(Sink *k);
  46. void sinkFree(Sink *k);
  47. DirSink *dirSinkAlloc(VtSession *z, int psize, int dsize);
  48. void dirSinkWrite(DirSink *k, VtEntry*);
  49. void dirSinkWriteSink(DirSink *k, Sink*);
  50. int dirSinkWriteFile(DirSink *k, VacFile *vf);
  51. void dirSinkClose(DirSink *k);
  52. void dirSinkFree(DirSink *k);
  53. MetaSink *metaSinkAlloc(VtSession *z, int psize, int dsize);
  54. void metaSinkPutc(MetaSink *k, int c);
  55. void metaSinkPutString(MetaSink *k, char *s);
  56. void metaSinkPutUint32(MetaSink *k, ulong x);
  57. void metaSinkPutUint64(MetaSink *k, uvlong x);
  58. void metaSinkWrite(MetaSink *k, uchar *data, int n);
  59. void metaSinkWriteDir(MetaSink *ms, VacDir *vd);
  60. void metaSinkEOR(MetaSink *k);
  61. void metaSinkClose(MetaSink *k);
  62. void metaSinkFree(MetaSink *k);
  63. void plan9ToVacDir(VacDir*, Dir*, ulong entry, uvlong qid);
  64. enum {
  65. Version = 8,
  66. BlockSize = 8*1024,
  67. MaxExclude = 1000,
  68. };
  69. struct {
  70. ulong file;
  71. ulong sfile;
  72. ulong data;
  73. ulong sdata;
  74. ulong skip;
  75. ulong meta;
  76. } stats;
  77. int bsize = BlockSize;
  78. int maxbsize;
  79. char *oname, *dfile;
  80. int verbose;
  81. uvlong fileid = 1;
  82. int qdiff;
  83. char *exclude[MaxExclude];
  84. int nexclude;
  85. int nowrite;
  86. int merge;
  87. char *isi;
  88. void
  89. main(int argc, char *argv[])
  90. {
  91. VtSession *z;
  92. char *p;
  93. char *host = nil;
  94. int statsFlag = 0;
  95. atexit(cleanup);
  96. ARGBEGIN{
  97. default:
  98. usage();
  99. case 'b':
  100. p = ARGF();
  101. if(p == 0)
  102. usage();
  103. bsize = unittoull(p);
  104. if(bsize == ~0)
  105. usage();
  106. break;
  107. case 'd':
  108. dfile = ARGF();
  109. if(dfile == nil)
  110. usage();
  111. break;
  112. case 'e':
  113. if(nexclude >= MaxExclude)
  114. sysfatal("too many exclusions");
  115. exclude[nexclude] = ARGF();
  116. if(exclude[nexclude] == nil)
  117. usage();
  118. nexclude++;
  119. break;
  120. case 'f':
  121. oname = ARGF();
  122. if(oname == 0)
  123. usage();
  124. break;
  125. case 'h':
  126. host = ARGF();
  127. if(host == nil)
  128. usage();
  129. break;
  130. case 'i':
  131. isi = ARGF();
  132. if(isi == nil)
  133. usage();
  134. break;
  135. case 'n':
  136. nowrite++;
  137. break;
  138. case 'm':
  139. merge++;
  140. break;
  141. case 'q':
  142. qdiff++;
  143. break;
  144. case 's':
  145. statsFlag++;
  146. break;
  147. case 'v':
  148. verbose++;
  149. break;
  150. }ARGEND;
  151. if(bsize < 512)
  152. bsize = 512;
  153. if(bsize > VtMaxLumpSize)
  154. bsize = VtMaxLumpSize;
  155. maxbsize = bsize;
  156. vtAttach();
  157. fmtinstall('V', vtScoreFmt);
  158. fmtinstall('R', vtErrFmt);
  159. z = vtDial(host, 0);
  160. if(z == nil)
  161. vtFatal("could not connect to server: %R");
  162. if(!vtConnect(z, 0))
  163. vtFatal("vtConnect: %R");
  164. qsort(exclude, nexclude, sizeof(char*), strpCmp);
  165. vac(z, argv);
  166. if(!vtSync(z))
  167. fprint(2, "warning: could not ask server to flush pending writes: %R\n");
  168. if(statsFlag)
  169. fprint(2, "files %ld:%ld data %ld:%ld:%ld meta %ld\n", stats.file, stats.sfile,
  170. stats.data, stats.skip, stats.sdata, stats.meta);
  171. //packetStats();
  172. vtClose(z);
  173. vtDetach();
  174. exits(0);
  175. }
  176. void
  177. static usage(void)
  178. {
  179. fprint(2, "usage: %s [-amqsv] [-h host] [-d vacfile] [-b blocksize] [-i name] [-e exclude] [-f vacfile] file ... \n", argv0);
  180. exits("usage");
  181. }
  182. static
  183. int strpCmp(void *p0, void *p1)
  184. {
  185. return strcmp(*(char**)p0, *(char**)p1);
  186. }
  187. int
  188. readBlock(int fd, uchar *buf, int n)
  189. {
  190. int m, t = 0;
  191. while(t < n){
  192. m = read(fd, buf+t, n-t);
  193. if(m < 0)
  194. return -1;
  195. if(m == 0)
  196. break;
  197. t += m;
  198. }
  199. return t;
  200. }
  201. int
  202. vacWrite(VtSession *z, uchar score[VtScoreSize], int type, uchar *buf, int n)
  203. {
  204. assert(n > 0);
  205. if(nowrite) {
  206. vtSha1(score, buf, n);
  207. return 1;
  208. }
  209. if(!vtWrite(z, score, type, buf, n))
  210. return 0;
  211. if(!vtSha1Check(score, buf, n)) {
  212. uchar score2[VtScoreSize];
  213. vtSha1(score2, buf, n);
  214. fprint(2, "vtSha1Check: n = %d %V %V\n", n, score, score2);
  215. vtSetError("vtSha1Check failed");
  216. return 0;
  217. }
  218. return 1;
  219. }
  220. static int
  221. vac(VtSession *z, char *argv[])
  222. {
  223. DirSink *dsink, *ds;
  224. MetaSink *ms;
  225. VtRoot root;
  226. uchar score[VtScoreSize], buf[VtRootSize];
  227. char cwd[2048];
  228. int cd, i;
  229. char *cp2, *cp;
  230. VacFS *fs;
  231. VacFile *vff;
  232. int fd;
  233. Dir *dir;
  234. VacDir vd;
  235. if(getwd(cwd, sizeof(cwd)) == 0)
  236. sysfatal("can't find current directory: %r");
  237. dsink = dirSinkAlloc(z, bsize, bsize);
  238. fs = nil;
  239. if(dfile != nil) {
  240. fs = vfsOpen(z, dfile, 1, 10000);
  241. if(fs == nil)
  242. fprint(2, "could not open diff: %s: %s\n", dfile, vtGetError());
  243. }
  244. if(oname != nil) {
  245. fd = create(oname, OWRITE, 0666);
  246. if(fd < 0)
  247. sysfatal("could not create file: %s: %r", oname);
  248. } else
  249. fd = 1;
  250. dir = dirfstat(fd);
  251. if(dir == nil)
  252. sysfatal("dirfstat failed: %r");
  253. for(; *argv; argv++) {
  254. cp2 = *argv;
  255. cd = 0;
  256. for (cp = *argv; *cp; cp++)
  257. if (*cp == '/')
  258. cp2 = cp;
  259. if (cp2 != *argv) {
  260. *cp2 = '\0';
  261. if (chdir(*argv) < 0)
  262. sysfatal("can't cd to %s: %r", *argv);
  263. *cp2 = '/';
  264. cp2++;
  265. cd = 1;
  266. }
  267. vff = nil;
  268. if(fs)
  269. vff = vfOpen(fs, cp2);
  270. vacFile(dsink, argv[0], cp2, vff);
  271. if(vff)
  272. vfDecRef(vff);
  273. if(cd && chdir(cwd) < 0)
  274. sysfatal("can't cd back to %s: %r", cwd);
  275. }
  276. if(isi) {
  277. vff = nil;
  278. if(fs)
  279. vff = vfOpen(fs, isi);
  280. vacStdin(dsink, isi, vff);
  281. if(vff)
  282. vfDecRef(vff);
  283. }
  284. dirSinkClose(dsink);
  285. /* build meta information for the root */
  286. ms = metaSinkAlloc(z, bsize, bsize);
  287. /* fake into a directory */
  288. dir->mode |= (dir->mode&0444)>>2;
  289. dir->qid.type |= QTDIR;
  290. dir->mode |= DMDIR;
  291. plan9ToVacDir(&vd, dir, 0, fileid++);
  292. if(strcmp(vd.elem, "/") == 0){
  293. vtMemFree(vd.elem);
  294. vd.elem = vtStrDup("root");
  295. }
  296. metaSinkWriteDir(ms, &vd);
  297. vdCleanup(&vd);
  298. metaSinkClose(ms);
  299. ds = dirSinkAlloc(z, bsize, bsize);
  300. dirSinkWriteSink(ds, dsink->sink);
  301. dirSinkWriteSink(ds, dsink->msink->sink);
  302. dirSinkWriteSink(ds, ms->sink);
  303. dirSinkClose(ds);
  304. memset(&root, 0, sizeof(root));
  305. root.version = VtRootVersion;
  306. strncpy(root.name, dir->name, sizeof(root.name));
  307. root.name[sizeof(root.name)-1] = 0;
  308. free(dir);
  309. sprint(root.type, "vac");
  310. memmove(root.score, ds->sink->dir.score, VtScoreSize);
  311. root.blockSize = maxbsize;
  312. if(fs != nil)
  313. vfsGetScore(fs, root.prev);
  314. metaSinkFree(ms);
  315. dirSinkFree(ds);
  316. dirSinkFree(dsink);
  317. if(fs != nil)
  318. vfsClose(fs);
  319. vtRootPack(&root, buf);
  320. if(!vacWrite(z, score, VtRootType, buf, VtRootSize))
  321. vtFatal("vacWrite failed: %s", vtGetError());
  322. fprint(fd, "vac:");
  323. for(i=0; i<VtScoreSize; i++)
  324. fprint(fd, "%.2x", score[i]);
  325. fprint(fd, "\n");
  326. /* avoid remove at cleanup */
  327. oname = nil;
  328. return 1;
  329. }
  330. static int
  331. isExcluded(char *name)
  332. {
  333. int bot, top, i, x;
  334. bot = 0;
  335. top = nexclude;
  336. while(bot < top) {
  337. i = (bot+top)>>1;
  338. x = strcmp(exclude[i], name);
  339. if(x == 0)
  340. return 1;
  341. if(x < 0)
  342. bot = i + 1;
  343. else /* x > 0 */
  344. top = i;
  345. }
  346. return 0;
  347. }
  348. static void
  349. vacFile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
  350. {
  351. int fd;
  352. Dir *dir;
  353. VacDir vd;
  354. ulong entry;
  355. if(isExcluded(lname)) {
  356. warn("excluding: %s", lname);
  357. return;
  358. }
  359. if(merge && vacMerge(dsink, lname, sname))
  360. return;
  361. fd = open(sname, OREAD);
  362. if(fd < 0) {
  363. warn("could not open file: %s: %s", lname, vtOSError());
  364. return;
  365. }
  366. if(verbose)
  367. fprint(2, "%s\n", lname);
  368. dir = dirfstat(fd);
  369. if(dir == nil) {
  370. warn("can't stat %s: %r", lname);
  371. close(fd);
  372. return;
  373. }
  374. entry = dsink->nentry;
  375. if(dir->mode & DMDIR)
  376. vacDir(dsink, fd, lname, sname, vf);
  377. else
  378. vacData(dsink, fd, lname, vf, dir);
  379. plan9ToVacDir(&vd, dir, entry, fileid++);
  380. metaSinkWriteDir(dsink->msink, &vd);
  381. vdCleanup(&vd);
  382. free(dir);
  383. close(fd);
  384. }
  385. static void
  386. vacStdin(DirSink *dsink, char *name, VacFile *vf)
  387. {
  388. Dir *dir;
  389. VacDir vd;
  390. ulong entry;
  391. if(verbose)
  392. fprint(2, "%s\n", "<stdio>");
  393. dir = dirfstat(0);
  394. if(dir == nil) {
  395. warn("can't stat <stdio>: %r");
  396. return;
  397. }
  398. entry = dsink->nentry;
  399. vacData(dsink, 0, "<stdin>", vf, dir);
  400. plan9ToVacDir(&vd, dir, entry, fileid++);
  401. vd.elem = vtStrDup(name);
  402. metaSinkWriteDir(dsink->msink, &vd);
  403. vdCleanup(&vd);
  404. free(dir);
  405. }
  406. static ulong
  407. vacDataSkip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname)
  408. {
  409. int n;
  410. ulong i;
  411. uchar score[VtScoreSize];
  412. /* skip blocks for append only files */
  413. if(seek(fd, (blocks-1)*bsize, 0) != (blocks-1)*bsize) {
  414. warn("error seeking: %s", lname);
  415. goto Err;
  416. }
  417. n = readBlock(fd, buf, bsize);
  418. if(n < bsize) {
  419. warn("error checking append only file: %s", lname);
  420. goto Err;
  421. }
  422. if(!vfGetBlockScore(vf, blocks-1, score) || !vtSha1Check(score, buf, n)) {
  423. warn("last block of append file did not match: %s", lname);
  424. goto Err;
  425. }
  426. for(i=0; i<blocks; i++) {
  427. if(!vfGetBlockScore(vf, i, score)) {
  428. warn("could not get score: %s: %lud", lname, i);
  429. seek(fd, i*bsize, 0);
  430. return i;
  431. }
  432. stats.skip++;
  433. sinkWriteScore(sink, score, bsize);
  434. }
  435. return i;
  436. Err:
  437. seek(fd, 0, 0);
  438. return 0;
  439. }
  440. static void
  441. vacData(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir)
  442. {
  443. uchar *buf;
  444. Sink *sink;
  445. int n;
  446. uchar score[VtScoreSize];
  447. ulong block, same;
  448. VacDir vd;
  449. ulong vfblocks;
  450. vfblocks = 0;
  451. if(vf != nil && qdiff) {
  452. vfGetDir(vf, &vd);
  453. if(vd.mtime == dir->mtime)
  454. if(vd.size == dir->length)
  455. if(!vd.plan9 || /* vd.p9path == dir->qid.path && */ vd.p9version == dir->qid.vers)
  456. if(dirSinkWriteFile(dsink, vf)) {
  457. stats.sfile++;
  458. vdCleanup(&vd);
  459. return;
  460. }
  461. /* look for an append only file */
  462. if((dir->mode&DMAPPEND) != 0)
  463. if(vd.size < dir->length)
  464. if(vd.plan9)
  465. if(vd.p9path == dir->qid.path)
  466. vfblocks = vd.size/bsize;
  467. vdCleanup(&vd);
  468. }
  469. stats.file++;
  470. buf = vtMemAlloc(bsize);
  471. sink = sinkAlloc(dsink->sink->z, bsize, bsize);
  472. block = 0;
  473. same = stats.sdata+stats.skip;
  474. if(vfblocks > 1)
  475. block += vacDataSkip(sink, vf, fd, vfblocks, buf, lname);
  476. if(0) fprint(2, "vacData: %s: %ld\n", lname, block);
  477. for(;;) {
  478. n = readBlock(fd, buf, bsize);
  479. if(0 && n < 0)
  480. warn("file truncated due to read error: %s: %s", lname, vtOSError());
  481. if(n <= 0)
  482. break;
  483. if(vf != nil && vfGetBlockScore(vf, block, score) && vtSha1Check(score, buf, n)) {
  484. stats.sdata++;
  485. sinkWriteScore(sink, score, n);
  486. } else
  487. sinkWrite(sink, buf, n);
  488. block++;
  489. }
  490. same = stats.sdata+stats.skip - same;
  491. if(same && (dir->mode&DMAPPEND) != 0)
  492. if(0)fprint(2, "%s: total %lud same %lud:%lud diff %lud\n",
  493. lname, block, same, vfblocks, block-same);
  494. sinkClose(sink);
  495. dirSinkWriteSink(dsink, sink);
  496. sinkFree(sink);
  497. free(buf);
  498. }
  499. static void
  500. vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf)
  501. {
  502. Dir *dirs;
  503. char *ln, *sn;
  504. int i, nd;
  505. DirSink *ds;
  506. VacFile *vvf;
  507. char *name;
  508. ds = dirSinkAlloc(dsink->sink->z, bsize, bsize);
  509. while((nd = dirread(fd, &dirs)) > 0){
  510. for(i = 0; i < nd; i++){
  511. name = dirs[i].name;
  512. /* check for bad file names */
  513. if(name[0] == 0 || strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
  514. continue;
  515. ln = vtMemAlloc(strlen(lname) + strlen(name) + 2);
  516. sn = vtMemAlloc(strlen(sname) + strlen(name) + 2);
  517. sprint(ln, "%s/%s", lname, name);
  518. sprint(sn, "%s/%s", sname, name);
  519. if(vf != nil)
  520. vvf = vfWalk(vf, name);
  521. else
  522. vvf = nil;
  523. vacFile(ds, ln, sn, vvf);
  524. if(vvf != nil)
  525. vfDecRef(vvf);
  526. vtMemFree(ln);
  527. vtMemFree(sn);
  528. }
  529. free(dirs);
  530. }
  531. dirSinkClose(ds);
  532. dirSinkWriteSink(dsink, ds->sink);
  533. dirSinkWriteSink(dsink, ds->msink->sink);
  534. dirSinkFree(ds);
  535. }
  536. static int
  537. vacMergeFile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max)
  538. {
  539. uchar buf[VtEntrySize];
  540. VtEntry dd, md;
  541. int e;
  542. if(vfRead(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) {
  543. warn("could not read venti dir entry: %s\n", dir->elem);
  544. return 0;
  545. }
  546. vtEntryUnpack(&dd, buf, 0);
  547. if(dir->mode & ModeDir) {
  548. e = dir->mentry;
  549. if(e == 0)
  550. e = dir->entry + 1;
  551. if(vfRead(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) {
  552. warn("could not read venti dir entry: %s\n", dir->elem);
  553. return 0;
  554. }
  555. vtEntryUnpack(&md, buf, 0);
  556. }
  557. /* max might incorrect in some old dumps */
  558. if(dir->qid >= *max) {
  559. warn("qid out of range: %s", dir->elem);
  560. *max = dir->qid;
  561. }
  562. dir->qid += offset;
  563. dir->entry = dsink->nentry;
  564. if(dir->qidSpace) {
  565. dir->qidOffset += offset;
  566. } else {
  567. dir->qidSpace = 1;
  568. dir->qidOffset = offset;
  569. dir->qidMax = *max;
  570. }
  571. dirSinkWrite(dsink, &dd);
  572. if(dir->mode & ModeDir)
  573. dirSinkWrite(dsink, &md);
  574. metaSinkWriteDir(dsink->msink, dir);
  575. return 1;
  576. }
  577. static int
  578. vacMerge(DirSink *dsink, char *lname, char *sname)
  579. {
  580. char *p;
  581. VacFS *fs;
  582. VacFile *vf;
  583. VacDirEnum *d;
  584. VacDir dir;
  585. uvlong max;
  586. p = strrchr(sname, '.');
  587. if(p == 0 || strcmp(p, ".vac"))
  588. return 0;
  589. d = nil;
  590. fs = vfsOpen(dsink->sink->z, sname, 1, 100);
  591. if(fs == nil)
  592. return 0;
  593. vf = vfOpen(fs, "/");
  594. if(vf == nil)
  595. goto Done;
  596. max = vfGetId(vf);
  597. d = vdeOpen(fs, "/");
  598. if(d == nil)
  599. goto Done;
  600. if(verbose)
  601. fprint(2, "merging: %s\n", lname);
  602. if(maxbsize < vfsGetBlockSize(fs))
  603. maxbsize = vfsGetBlockSize(fs);
  604. for(;;) {
  605. if(vdeRead(d, &dir, 1) < 1)
  606. break;
  607. vacMergeFile(dsink, vf, &dir, fileid, &max);
  608. vdCleanup(&dir);
  609. }
  610. fileid += max;
  611. Done:
  612. if(d != nil)
  613. vdeFree(d);
  614. if(vf != nil)
  615. vfDecRef(vf);
  616. vfsClose(fs);
  617. return 1;
  618. }
  619. Sink *
  620. sinkAlloc(VtSession *z, int psize, int dsize)
  621. {
  622. Sink *k;
  623. int i;
  624. if(psize < 512 || psize > VtMaxLumpSize)
  625. vtFatal("sinkAlloc: bad psize");
  626. if(dsize < 512 || dsize > VtMaxLumpSize)
  627. vtFatal("sinkAlloc: bad psize");
  628. psize = VtScoreSize*(psize/VtScoreSize);
  629. k = vtMemAllocZ(sizeof(Sink));
  630. k->z = z;
  631. k->dir.flags = VtEntryActive;
  632. k->dir.psize = psize;
  633. k->dir.dsize = dsize;
  634. k->buf = vtMemAllocZ(VtPointerDepth*k->dir.psize + VtScoreSize);
  635. for(i=0; i<=VtPointerDepth; i++)
  636. k->pbuf[i] = k->buf + i*k->dir.psize;
  637. return k;
  638. }
  639. void
  640. sinkWriteScore(Sink *k, uchar score[VtScoreSize], int n)
  641. {
  642. int i;
  643. uchar *p;
  644. VtEntry *d;
  645. memmove(k->pbuf[0], score, VtScoreSize);
  646. d = &k->dir;
  647. for(i=0; i<VtPointerDepth; i++) {
  648. k->pbuf[i] += VtScoreSize;
  649. if(k->pbuf[i] < k->buf + d->psize*(i+1))
  650. break;
  651. if(i == VtPointerDepth-1)
  652. vtFatal("file too big");
  653. p = k->buf+i*d->psize;
  654. stats.meta++;
  655. if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, d->psize))
  656. vtFatal("vacWrite failed: %s", vtGetError());
  657. k->pbuf[i] = p;
  658. }
  659. /* round size up to multiple of dsize */
  660. d->size = d->dsize * ((d->size + d->dsize-1)/d->dsize);
  661. d->size += n;
  662. }
  663. void
  664. sinkWrite(Sink *k, uchar *p, int n)
  665. {
  666. int type;
  667. uchar score[VtScoreSize];
  668. if(n > k->dir.dsize)
  669. vtFatal("sinkWrite: size too big");
  670. if(k->dir.flags & VtEntryDir) {
  671. type = VtDirType;
  672. stats.meta++;
  673. } else {
  674. type = VtDataType;
  675. stats.data++;
  676. }
  677. if(!vacWrite(k->z, score, type, p, n))
  678. vtFatal("vacWrite failed: %s", vtGetError());
  679. sinkWriteScore(k, score, n);
  680. }
  681. static int
  682. sizeToDepth(uvlong s, int psize, int dsize)
  683. {
  684. int np;
  685. int d;
  686. /* determine pointer depth */
  687. np = psize/VtScoreSize;
  688. s = (s + dsize - 1)/dsize;
  689. for(d = 0; s > 1; d++)
  690. s = (s + np - 1)/np;
  691. return d;
  692. }
  693. void
  694. sinkClose(Sink *k)
  695. {
  696. int i, n;
  697. uchar *p;
  698. VtEntry *kd;
  699. kd = &k->dir;
  700. /* empty */
  701. if(kd->size == 0) {
  702. memmove(kd->score, vtZeroScore, VtScoreSize);
  703. return;
  704. }
  705. for(n=VtPointerDepth-1; n>0; n--)
  706. if(k->pbuf[n] > k->buf + kd->psize*n)
  707. break;
  708. kd->depth = sizeToDepth(kd->size, kd->psize, kd->dsize);
  709. /* skip full part of tree */
  710. for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
  711. ;
  712. /* is the tree completely full */
  713. if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
  714. memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
  715. return;
  716. }
  717. n++;
  718. /* clean up the edge */
  719. for(; i<n; i++) {
  720. p = k->buf+i*kd->psize;
  721. stats.meta++;
  722. if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, k->pbuf[i]-p))
  723. vtFatal("vacWrite failed: %s", vtGetError());
  724. k->pbuf[i+1] += VtScoreSize;
  725. }
  726. memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
  727. }
  728. void
  729. sinkFree(Sink *k)
  730. {
  731. vtMemFree(k->buf);
  732. vtMemFree(k);
  733. }
  734. DirSink *
  735. dirSinkAlloc(VtSession *z, int psize, int dsize)
  736. {
  737. DirSink *k;
  738. int ds;
  739. ds = VtEntrySize*(dsize/VtEntrySize);
  740. k = vtMemAllocZ(sizeof(DirSink));
  741. k->sink = sinkAlloc(z, psize, ds);
  742. k->sink->dir.flags |= VtEntryDir;
  743. k->msink = metaSinkAlloc(z, psize, dsize);
  744. k->buf = vtMemAlloc(ds);
  745. k->p = k->buf;
  746. k->ep = k->buf + ds;
  747. return k;
  748. }
  749. void
  750. dirSinkWrite(DirSink *k, VtEntry *dir)
  751. {
  752. if(k->p + VtEntrySize > k->ep) {
  753. sinkWrite(k->sink, k->buf, k->p - k->buf);
  754. k->p = k->buf;
  755. }
  756. vtEntryPack(dir, k->p, 0);
  757. k->nentry++;
  758. k->p += VtEntrySize;
  759. }
  760. void
  761. dirSinkWriteSink(DirSink *k, Sink *sink)
  762. {
  763. dirSinkWrite(k, &sink->dir);
  764. }
  765. int
  766. dirSinkWriteFile(DirSink *k, VacFile *vf)
  767. {
  768. VtEntry dir;
  769. if(!vfGetVtEntry(vf, &dir))
  770. return 0;
  771. dirSinkWrite(k, &dir);
  772. return 1;
  773. }
  774. void
  775. dirSinkClose(DirSink *k)
  776. {
  777. metaSinkClose(k->msink);
  778. if(k->p != k->buf)
  779. sinkWrite(k->sink, k->buf, k->p - k->buf);
  780. sinkClose(k->sink);
  781. }
  782. void
  783. dirSinkFree(DirSink *k)
  784. {
  785. sinkFree(k->sink);
  786. metaSinkFree(k->msink);
  787. vtMemFree(k->buf);
  788. vtMemFree(k);
  789. }
  790. MetaSink *
  791. metaSinkAlloc(VtSession *z, int psize, int dsize)
  792. {
  793. MetaSink *k;
  794. k = vtMemAllocZ(sizeof(MetaSink));
  795. k->sink = sinkAlloc(z, psize, dsize);
  796. k->buf = vtMemAlloc(dsize);
  797. k->maxindex = dsize/100; /* 100 byte entries seems reasonable */
  798. if(k->maxindex < 1)
  799. k->maxindex = 1;
  800. k->rp = k->p = k->buf + MetaHeaderSize + k->maxindex*MetaIndexSize;
  801. k->ep = k->buf + dsize;
  802. return k;
  803. }
  804. /* hack to get base to compare routine - not reentrant */
  805. uchar *blockBase;
  806. int
  807. dirCmp(void *p0, void *p1)
  808. {
  809. uchar *q0, *q1;
  810. int n0, n1, r;
  811. /* name is first element of entry */
  812. q0 = p0;
  813. q0 = blockBase + (q0[0]<<8) + q0[1];
  814. n0 = (q0[6]<<8) + q0[7];
  815. q0 += 8;
  816. q1 = p1;
  817. q1 = blockBase + (q1[0]<<8) + q1[1];
  818. n1 = (q1[6]<<8) + q1[7];
  819. q1 += 8;
  820. if(n0 == n1)
  821. return memcmp(q0, q1, n0);
  822. else if (n0 < n1) {
  823. r = memcmp(q0, q1, n0);
  824. return (r==0)?1:r;
  825. } else {
  826. r = memcmp(q0, q1, n1);
  827. return (r==0)?-1:r;
  828. }
  829. }
  830. void
  831. metaSinkFlush(MetaSink *k)
  832. {
  833. uchar *p;
  834. int n;
  835. MetaBlock mb;
  836. if(k->nindex == 0)
  837. return;
  838. assert(k->nindex <= k->maxindex);
  839. p = k->buf;
  840. n = k->rp - p;
  841. mb.size = n;
  842. mb.free = 0;
  843. mb.nindex = k->nindex;
  844. mb.maxindex = k->maxindex;
  845. mb.buf = p;
  846. mbPack(&mb);
  847. p += MetaHeaderSize;
  848. /* XXX this is not reentrant! */
  849. blockBase = k->buf;
  850. qsort(p, k->nindex, MetaIndexSize, dirCmp);
  851. p += k->nindex*MetaIndexSize;
  852. memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize);
  853. p += (k->maxindex-k->nindex)*MetaIndexSize;
  854. sinkWrite(k->sink, k->buf, n);
  855. /* move down partial entry */
  856. n = k->p - k->rp;
  857. memmove(p, k->rp, n);
  858. k->rp = p;
  859. k->p = p + n;
  860. k->nindex = 0;
  861. }
  862. void
  863. metaSinkPutc(MetaSink *k, int c)
  864. {
  865. if(k->p+1 > k->ep)
  866. metaSinkFlush(k);
  867. if(k->p+1 > k->ep)
  868. vtFatal("directory entry too large");
  869. k->p[0] = c;
  870. k->p++;
  871. }
  872. void
  873. metaSinkPutString(MetaSink *k, char *s)
  874. {
  875. int n = strlen(s);
  876. metaSinkPutc(k, n>>8);
  877. metaSinkPutc(k, n);
  878. metaSinkWrite(k, (uchar*)s, n);
  879. }
  880. void
  881. metaSinkPutUint32(MetaSink *k, ulong x)
  882. {
  883. metaSinkPutc(k, x>>24);
  884. metaSinkPutc(k, x>>16);
  885. metaSinkPutc(k, x>>8);
  886. metaSinkPutc(k, x);
  887. }
  888. void
  889. metaSinkPutUint64(MetaSink *k, uvlong x)
  890. {
  891. metaSinkPutUint32(k, x>>32);
  892. metaSinkPutUint32(k, x);
  893. }
  894. void
  895. metaSinkWrite(MetaSink *k, uchar *data, int n)
  896. {
  897. if(k->p + n > k->ep)
  898. metaSinkFlush(k);
  899. if(k->p + n > k->ep)
  900. vtFatal("directory entry too large");
  901. memmove(k->p, data, n);
  902. k->p += n;
  903. }
  904. void
  905. metaSinkWriteDir(MetaSink *ms, VacDir *dir)
  906. {
  907. metaSinkPutUint32(ms, DirMagic);
  908. metaSinkPutc(ms, Version>>8);
  909. metaSinkPutc(ms, Version);
  910. metaSinkPutString(ms, dir->elem);
  911. metaSinkPutUint32(ms, dir->entry);
  912. metaSinkPutUint64(ms, dir->qid);
  913. metaSinkPutString(ms, dir->uid);
  914. metaSinkPutString(ms, dir->gid);
  915. metaSinkPutString(ms, dir->mid);
  916. metaSinkPutUint32(ms, dir->mtime);
  917. metaSinkPutUint32(ms, dir->mcount);
  918. metaSinkPutUint32(ms, dir->ctime);
  919. metaSinkPutUint32(ms, dir->atime);
  920. metaSinkPutUint32(ms, dir->mode);
  921. if(dir->plan9) {
  922. metaSinkPutc(ms, DirPlan9Entry); /* plan9 extra info */
  923. metaSinkPutc(ms, 0); /* plan9 extra size */
  924. metaSinkPutc(ms, 12); /* plan9 extra size */
  925. metaSinkPutUint64(ms, dir->p9path);
  926. metaSinkPutUint32(ms, dir->p9version);
  927. }
  928. if(dir->qidSpace != 0) {
  929. metaSinkPutc(ms, DirQidSpaceEntry);
  930. metaSinkPutc(ms, 0);
  931. metaSinkPutc(ms, 16);
  932. metaSinkPutUint64(ms, dir->qidOffset);
  933. metaSinkPutUint64(ms, dir->qidMax);
  934. }
  935. if(dir->gen != 0) {
  936. metaSinkPutc(ms, DirGenEntry);
  937. metaSinkPutc(ms, 0);
  938. metaSinkPutc(ms, 4);
  939. metaSinkPutUint32(ms, dir->gen);
  940. }
  941. metaSinkEOR(ms);
  942. }
  943. void
  944. plan9ToVacDir(VacDir *vd, Dir *dir, ulong entry, uvlong qid)
  945. {
  946. memset(vd, 0, sizeof(VacDir));
  947. vd->elem = vtStrDup(dir->name);
  948. vd->entry = entry;
  949. vd->qid = qid;
  950. vd->uid = vtStrDup(dir->uid);
  951. vd->gid = vtStrDup(dir->gid);
  952. vd->mid = vtStrDup(dir->muid);
  953. vd->mtime = dir->mtime;
  954. vd->mcount = 0;
  955. vd->ctime = dir->mtime; /* ctime: not available on plan 9 */
  956. vd->atime = dir->atime;
  957. vd->mode = dir->mode & 0777;
  958. if(dir->mode & DMDIR)
  959. vd->mode |= ModeDir;
  960. if(dir->mode & DMAPPEND)
  961. vd->mode |= ModeAppend;
  962. if(dir->mode & DMEXCL)
  963. vd->mode |= ModeExclusive;
  964. vd->plan9 = 1;
  965. vd->p9path = dir->qid.path;
  966. vd->p9version = dir->qid.vers;
  967. }
  968. void
  969. metaSinkEOR(MetaSink *k)
  970. {
  971. uchar *p;
  972. int o, n;
  973. p = k->buf + MetaHeaderSize;
  974. p += k->nindex * MetaIndexSize;
  975. o = k->rp-k->buf; /* offset from start of block */
  976. n = k->p-k->rp; /* size of entry */
  977. p[0] = o >> 8;
  978. p[1] = o;
  979. p[2] = n >> 8;
  980. p[3] = n;
  981. k->rp = k->p;
  982. k->nindex++;
  983. if(k->nindex == k->maxindex)
  984. metaSinkFlush(k);
  985. }
  986. void
  987. metaSinkClose(MetaSink *k)
  988. {
  989. metaSinkFlush(k);
  990. sinkClose(k->sink);
  991. }
  992. void
  993. metaSinkFree(MetaSink *k)
  994. {
  995. sinkFree(k->sink);
  996. vtMemFree(k->buf);
  997. vtMemFree(k);
  998. }
  999. static void
  1000. warn(char *fmt, ...)
  1001. {
  1002. va_list arg;
  1003. va_start(arg, fmt);
  1004. fprint(2, "%s: ", argv0);
  1005. vfprint(2, fmt, arg);
  1006. fprint(2, "\n");
  1007. va_end(arg);
  1008. }
  1009. static void
  1010. cleanup(void)
  1011. {
  1012. if(oname != nil)
  1013. remove(oname);
  1014. }
  1015. #define TWID64 ((u64int)~(u64int)0)
  1016. static u64int
  1017. unittoull(char *s)
  1018. {
  1019. char *es;
  1020. u64int n;
  1021. if(s == nil)
  1022. return TWID64;
  1023. n = strtoul(s, &es, 0);
  1024. if(*es == 'k' || *es == 'K'){
  1025. n *= 1024;
  1026. es++;
  1027. }else if(*es == 'm' || *es == 'M'){
  1028. n *= 1024*1024;
  1029. es++;
  1030. }else if(*es == 'g' || *es == 'G'){
  1031. n *= 1024*1024*1024;
  1032. es++;
  1033. }
  1034. if(*es != '\0')
  1035. return TWID64;
  1036. return n;
  1037. }