vac.c 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  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\n");
  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\n");
  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. chdir(*argv);
  262. *cp2 = '/';
  263. cp2++;
  264. cd = 1;
  265. }
  266. vff = nil;
  267. if(fs)
  268. vff = vfOpen(fs, cp2);
  269. vacFile(dsink, argv[0], cp2, vff);
  270. if(vff)
  271. vfDecRef(vff);
  272. if(cd && chdir(cwd) < 0)
  273. sysfatal("can't cd back to %s: %r\n", cwd);
  274. }
  275. if(isi) {
  276. vff = nil;
  277. if(fs)
  278. vff = vfOpen(fs, isi);
  279. vacStdin(dsink, isi, vff);
  280. if(vff)
  281. vfDecRef(vff);
  282. }
  283. dirSinkClose(dsink);
  284. /* build meta information for the root */
  285. ms = metaSinkAlloc(z, bsize, bsize);
  286. /* fake into a directory */
  287. dir->mode |= (dir->mode&0444)>>2;
  288. dir->qid.type |= QTDIR;
  289. dir->mode |= DMDIR;
  290. plan9ToVacDir(&vd, dir, 0, fileid++);
  291. if(strcmp(vd.elem, "/") == 0){
  292. vtMemFree(vd.elem);
  293. vd.elem = vtStrDup("root");
  294. }
  295. metaSinkWriteDir(ms, &vd);
  296. vdCleanup(&vd);
  297. metaSinkClose(ms);
  298. ds = dirSinkAlloc(z, bsize, bsize);
  299. dirSinkWriteSink(ds, dsink->sink);
  300. dirSinkWriteSink(ds, dsink->msink->sink);
  301. dirSinkWriteSink(ds, ms->sink);
  302. dirSinkClose(ds);
  303. memset(&root, 0, sizeof(root));
  304. root.version = VtRootVersion;
  305. strncpy(root.name, dir->name, sizeof(root.name));
  306. root.name[sizeof(root.name)-1] = 0;
  307. free(dir);
  308. sprint(root.type, "vac");
  309. memmove(root.score, ds->sink->dir.score, VtScoreSize);
  310. root.blockSize = maxbsize;
  311. if(fs != nil)
  312. vfsGetScore(fs, root.prev);
  313. metaSinkFree(ms);
  314. dirSinkFree(ds);
  315. dirSinkFree(dsink);
  316. if(fs != nil)
  317. vfsClose(fs);
  318. vtRootPack(&root, buf);
  319. if(!vacWrite(z, score, VtRootType, buf, VtRootSize))
  320. vtFatal("vacWrite failed: %s", vtGetError());
  321. fprint(fd, "vac:");
  322. for(i=0; i<VtScoreSize; i++)
  323. fprint(fd, "%.2x", score[i]);
  324. fprint(fd, "\n");
  325. /* avoid remove at cleanup */
  326. oname = nil;
  327. return 1;
  328. }
  329. static int
  330. isExcluded(char *name)
  331. {
  332. int bot, top, i, x;
  333. bot = 0;
  334. top = nexclude;
  335. while(bot < top) {
  336. i = (bot+top)>>1;
  337. x = strcmp(exclude[i], name);
  338. if(x == 0)
  339. return 1;
  340. if(x < 0)
  341. bot = i + 1;
  342. else /* x > 0 */
  343. top = i;
  344. }
  345. return 0;
  346. }
  347. static void
  348. vacFile(DirSink *dsink, char *lname, char *sname, VacFile *vf)
  349. {
  350. int fd;
  351. Dir *dir;
  352. VacDir vd;
  353. ulong entry;
  354. if(isExcluded(lname)) {
  355. warn("excluding: %s", lname);
  356. return;
  357. }
  358. if(merge && vacMerge(dsink, lname, sname))
  359. return;
  360. fd = open(sname, OREAD);
  361. if(fd < 0) {
  362. warn("could not open file: %s: %s", lname, vtOSError());
  363. return;
  364. }
  365. if(verbose)
  366. fprint(2, "%s\n", lname);
  367. dir = dirfstat(fd);
  368. if(dir == nil) {
  369. warn("can't stat %s: %r", lname);
  370. close(fd);
  371. return;
  372. }
  373. entry = dsink->nentry;
  374. if(dir->mode & DMDIR)
  375. vacDir(dsink, fd, lname, sname, vf);
  376. else
  377. vacData(dsink, fd, lname, vf, dir);
  378. plan9ToVacDir(&vd, dir, entry, fileid++);
  379. metaSinkWriteDir(dsink->msink, &vd);
  380. vdCleanup(&vd);
  381. free(dir);
  382. close(fd);
  383. }
  384. static void
  385. vacStdin(DirSink *dsink, char *name, VacFile *vf)
  386. {
  387. Dir *dir;
  388. VacDir vd;
  389. ulong entry;
  390. if(verbose)
  391. fprint(2, "%s\n", "<stdio>");
  392. dir = dirfstat(0);
  393. if(dir == nil) {
  394. warn("can't stat <stdio>: %r");
  395. return;
  396. }
  397. entry = dsink->nentry;
  398. vacData(dsink, 0, "<stdin>", vf, dir);
  399. plan9ToVacDir(&vd, dir, entry, fileid++);
  400. vd.elem = vtStrDup(name);
  401. metaSinkWriteDir(dsink->msink, &vd);
  402. vdCleanup(&vd);
  403. free(dir);
  404. }
  405. static ulong
  406. vacDataSkip(Sink *sink, VacFile *vf, int fd, ulong blocks, uchar *buf, char *lname)
  407. {
  408. int n;
  409. ulong i;
  410. uchar score[VtScoreSize];
  411. /* skip blocks for append only files */
  412. if(seek(fd, (blocks-1)*bsize, 0) != (blocks-1)*bsize) {
  413. warn("error seeking: %s", lname);
  414. goto Err;
  415. }
  416. n = readBlock(fd, buf, bsize);
  417. if(n < bsize) {
  418. warn("error checking append only file: %s", lname);
  419. goto Err;
  420. }
  421. if(!vfGetBlockScore(vf, blocks-1, score) || !vtSha1Check(score, buf, n)) {
  422. warn("last block of append file did not match: %s", lname);
  423. goto Err;
  424. }
  425. for(i=0; i<blocks; i++) {
  426. if(!vfGetBlockScore(vf, i, score)) {
  427. warn("could not get score: %s: %lud", lname, i);
  428. seek(fd, i*bsize, 0);
  429. return i;
  430. }
  431. stats.skip++;
  432. sinkWriteScore(sink, score, bsize);
  433. }
  434. return i;
  435. Err:
  436. seek(fd, 0, 0);
  437. return 0;
  438. }
  439. static void
  440. vacData(DirSink *dsink, int fd, char *lname, VacFile *vf, Dir *dir)
  441. {
  442. uchar *buf;
  443. Sink *sink;
  444. int n;
  445. uchar score[VtScoreSize];
  446. ulong block, same;
  447. VacDir vd;
  448. ulong vfblocks;
  449. vfblocks = 0;
  450. if(vf != nil && qdiff) {
  451. vfGetDir(vf, &vd);
  452. if(vd.mtime == dir->mtime)
  453. if(vd.size == dir->length)
  454. if(!vd.plan9 || /* vd.p9path == dir->qid.path && */ vd.p9version == dir->qid.vers)
  455. if(dirSinkWriteFile(dsink, vf)) {
  456. stats.sfile++;
  457. vdCleanup(&vd);
  458. return;
  459. }
  460. /* look for an append only file */
  461. if((dir->mode&DMAPPEND) != 0)
  462. if(vd.size < dir->length)
  463. if(vd.plan9)
  464. if(vd.p9path == dir->qid.path)
  465. vfblocks = vd.size/bsize;
  466. vdCleanup(&vd);
  467. }
  468. stats.file++;
  469. buf = vtMemAlloc(bsize);
  470. sink = sinkAlloc(dsink->sink->z, bsize, bsize);
  471. block = 0;
  472. same = stats.sdata+stats.skip;
  473. if(vfblocks > 1)
  474. block += vacDataSkip(sink, vf, fd, vfblocks, buf, lname);
  475. if(0) fprint(2, "vacData: %s: %ld\n", lname, block);
  476. for(;;) {
  477. n = readBlock(fd, buf, bsize);
  478. if(0 && n < 0)
  479. warn("file truncated due to read error: %s: %s", lname, vtOSError());
  480. if(n <= 0)
  481. break;
  482. if(vf != nil && vfGetBlockScore(vf, block, score) && vtSha1Check(score, buf, n)) {
  483. stats.sdata++;
  484. sinkWriteScore(sink, score, n);
  485. } else
  486. sinkWrite(sink, buf, n);
  487. block++;
  488. }
  489. same = stats.sdata+stats.skip - same;
  490. if(same && (dir->mode&DMAPPEND) != 0)
  491. if(0)fprint(2, "%s: total %lud same %lud:%lud diff %lud\n",
  492. lname, block, same, vfblocks, block-same);
  493. sinkClose(sink);
  494. dirSinkWriteSink(dsink, sink);
  495. sinkFree(sink);
  496. free(buf);
  497. }
  498. static void
  499. vacDir(DirSink *dsink, int fd, char *lname, char *sname, VacFile *vf)
  500. {
  501. Dir *dirs;
  502. char *ln, *sn;
  503. int i, nd;
  504. DirSink *ds;
  505. VacFile *vvf;
  506. char *name;
  507. ds = dirSinkAlloc(dsink->sink->z, bsize, bsize);
  508. while((nd = dirread(fd, &dirs)) > 0){
  509. for(i = 0; i < nd; i++){
  510. name = dirs[i].name;
  511. /* check for bad file names */
  512. if(name[0] == 0 || strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
  513. continue;
  514. ln = vtMemAlloc(strlen(lname) + strlen(name) + 2);
  515. sn = vtMemAlloc(strlen(sname) + strlen(name) + 2);
  516. sprint(ln, "%s/%s", lname, name);
  517. sprint(sn, "%s/%s", sname, name);
  518. if(vf != nil)
  519. vvf = vfWalk(vf, name);
  520. else
  521. vvf = nil;
  522. vacFile(ds, ln, sn, vvf);
  523. if(vvf != nil)
  524. vfDecRef(vvf);
  525. vtMemFree(ln);
  526. vtMemFree(sn);
  527. }
  528. free(dirs);
  529. }
  530. dirSinkClose(ds);
  531. dirSinkWriteSink(dsink, ds->sink);
  532. dirSinkWriteSink(dsink, ds->msink->sink);
  533. dirSinkFree(ds);
  534. }
  535. static int
  536. vacMergeFile(DirSink *dsink, VacFile *vf, VacDir *dir, uvlong offset, uvlong *max)
  537. {
  538. uchar buf[VtEntrySize];
  539. VtEntry dd, md;
  540. int e;
  541. if(vfRead(vf, buf, VtEntrySize, (uvlong)dir->entry*VtEntrySize) != VtEntrySize) {
  542. warn("could not read venti dir entry: %s\n", dir->elem);
  543. return 0;
  544. }
  545. vtEntryUnpack(&dd, buf, 0);
  546. if(dir->mode & ModeDir) {
  547. e = dir->mentry;
  548. if(e == 0)
  549. e = dir->entry + 1;
  550. if(vfRead(vf, buf, VtEntrySize, e*VtEntrySize) != VtEntrySize) {
  551. warn("could not read venti dir entry: %s\n", dir->elem);
  552. return 0;
  553. }
  554. vtEntryUnpack(&md, buf, 0);
  555. }
  556. /* max might incorrect in some old dumps */
  557. if(dir->qid >= *max) {
  558. warn("qid out of range: %s", dir->elem);
  559. *max = dir->qid;
  560. }
  561. dir->qid += offset;
  562. dir->entry = dsink->nentry;
  563. if(dir->qidSpace) {
  564. dir->qidOffset += offset;
  565. } else {
  566. dir->qidSpace = 1;
  567. dir->qidOffset = offset;
  568. dir->qidMax = *max;
  569. }
  570. dirSinkWrite(dsink, &dd);
  571. if(dir->mode & ModeDir)
  572. dirSinkWrite(dsink, &md);
  573. metaSinkWriteDir(dsink->msink, dir);
  574. return 1;
  575. }
  576. static int
  577. vacMerge(DirSink *dsink, char *lname, char *sname)
  578. {
  579. char *p;
  580. VacFS *fs;
  581. VacFile *vf;
  582. VacDirEnum *d;
  583. VacDir dir;
  584. uvlong max;
  585. p = strrchr(sname, '.');
  586. if(p == 0 || strcmp(p, ".vac"))
  587. return 0;
  588. d = nil;
  589. fs = vfsOpen(dsink->sink->z, sname, 1, 100);
  590. if(fs == nil)
  591. return 0;
  592. vf = vfOpen(fs, "/");
  593. if(vf == nil)
  594. goto Done;
  595. max = vfGetId(vf);
  596. d = vdeOpen(fs, "/");
  597. if(d == nil)
  598. goto Done;
  599. if(verbose)
  600. fprint(2, "merging: %s\n", lname);
  601. if(maxbsize < vfsGetBlockSize(fs))
  602. maxbsize = vfsGetBlockSize(fs);
  603. for(;;) {
  604. if(vdeRead(d, &dir, 1) < 1)
  605. break;
  606. vacMergeFile(dsink, vf, &dir, fileid, &max);
  607. vdCleanup(&dir);
  608. }
  609. fileid += max;
  610. Done:
  611. if(d != nil)
  612. vdeFree(d);
  613. if(vf != nil)
  614. vfDecRef(vf);
  615. vfsClose(fs);
  616. return 1;
  617. }
  618. Sink *
  619. sinkAlloc(VtSession *z, int psize, int dsize)
  620. {
  621. Sink *k;
  622. int i;
  623. if(psize < 512 || psize > VtMaxLumpSize)
  624. vtFatal("sinkAlloc: bad psize");
  625. if(dsize < 512 || dsize > VtMaxLumpSize)
  626. vtFatal("sinkAlloc: bad psize");
  627. psize = VtScoreSize*(psize/VtScoreSize);
  628. k = vtMemAllocZ(sizeof(Sink));
  629. k->z = z;
  630. k->dir.flags = VtEntryActive;
  631. k->dir.psize = psize;
  632. k->dir.dsize = dsize;
  633. k->buf = vtMemAllocZ(VtPointerDepth*k->dir.psize + VtScoreSize);
  634. for(i=0; i<=VtPointerDepth; i++)
  635. k->pbuf[i] = k->buf + i*k->dir.psize;
  636. return k;
  637. }
  638. void
  639. sinkWriteScore(Sink *k, uchar score[VtScoreSize], int n)
  640. {
  641. int i;
  642. uchar *p;
  643. VtEntry *d;
  644. memmove(k->pbuf[0], score, VtScoreSize);
  645. d = &k->dir;
  646. for(i=0; i<VtPointerDepth; i++) {
  647. k->pbuf[i] += VtScoreSize;
  648. if(k->pbuf[i] < k->buf + d->psize*(i+1))
  649. break;
  650. if(i == VtPointerDepth-1)
  651. vtFatal("file too big");
  652. p = k->buf+i*d->psize;
  653. stats.meta++;
  654. if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, d->psize))
  655. vtFatal("vacWrite failed: %s", vtGetError());
  656. k->pbuf[i] = p;
  657. }
  658. /* round size up to multiple of dsize */
  659. d->size = d->dsize * ((d->size + d->dsize-1)/d->dsize);
  660. d->size += n;
  661. }
  662. void
  663. sinkWrite(Sink *k, uchar *p, int n)
  664. {
  665. int type;
  666. uchar score[VtScoreSize];
  667. if(n > k->dir.dsize)
  668. vtFatal("sinkWrite: size too big");
  669. if(k->dir.flags & VtEntryDir) {
  670. type = VtDirType;
  671. stats.meta++;
  672. } else {
  673. type = VtDataType;
  674. stats.data++;
  675. }
  676. if(!vacWrite(k->z, score, type, p, n))
  677. vtFatal("vacWrite failed: %s", vtGetError());
  678. sinkWriteScore(k, score, n);
  679. }
  680. static int
  681. sizeToDepth(uvlong s, int psize, int dsize)
  682. {
  683. int np;
  684. int d;
  685. /* determine pointer depth */
  686. np = psize/VtScoreSize;
  687. s = (s + dsize - 1)/dsize;
  688. for(d = 0; s > 1; d++)
  689. s = (s + np - 1)/np;
  690. return d;
  691. }
  692. void
  693. sinkClose(Sink *k)
  694. {
  695. int i, n;
  696. uchar *p;
  697. VtEntry *kd;
  698. kd = &k->dir;
  699. /* empty */
  700. if(kd->size == 0) {
  701. memmove(kd->score, vtZeroScore, VtScoreSize);
  702. return;
  703. }
  704. for(n=VtPointerDepth-1; n>0; n--)
  705. if(k->pbuf[n] > k->buf + kd->psize*n)
  706. break;
  707. kd->depth = sizeToDepth(kd->size, kd->psize, kd->dsize);
  708. /* skip full part of tree */
  709. for(i=0; i<n && k->pbuf[i] == k->buf + kd->psize*i; i++)
  710. ;
  711. /* is the tree completely full */
  712. if(i == n && k->pbuf[n] == k->buf + kd->psize*n + VtScoreSize) {
  713. memmove(kd->score, k->pbuf[n] - VtScoreSize, VtScoreSize);
  714. return;
  715. }
  716. n++;
  717. /* clean up the edge */
  718. for(; i<n; i++) {
  719. p = k->buf+i*kd->psize;
  720. stats.meta++;
  721. if(!vacWrite(k->z, k->pbuf[i+1], VtPointerType0+i, p, k->pbuf[i]-p))
  722. vtFatal("vacWrite failed: %s", vtGetError());
  723. k->pbuf[i+1] += VtScoreSize;
  724. }
  725. memmove(kd->score, k->pbuf[i] - VtScoreSize, VtScoreSize);
  726. }
  727. void
  728. sinkFree(Sink *k)
  729. {
  730. vtMemFree(k->buf);
  731. vtMemFree(k);
  732. }
  733. DirSink *
  734. dirSinkAlloc(VtSession *z, int psize, int dsize)
  735. {
  736. DirSink *k;
  737. int ds;
  738. ds = VtEntrySize*(dsize/VtEntrySize);
  739. k = vtMemAllocZ(sizeof(DirSink));
  740. k->sink = sinkAlloc(z, psize, ds);
  741. k->sink->dir.flags |= VtEntryDir;
  742. k->msink = metaSinkAlloc(z, psize, dsize);
  743. k->buf = vtMemAlloc(ds);
  744. k->p = k->buf;
  745. k->ep = k->buf + ds;
  746. return k;
  747. }
  748. void
  749. dirSinkWrite(DirSink *k, VtEntry *dir)
  750. {
  751. if(k->p + VtEntrySize > k->ep) {
  752. sinkWrite(k->sink, k->buf, k->p - k->buf);
  753. k->p = k->buf;
  754. }
  755. vtEntryPack(dir, k->p, 0);
  756. k->nentry++;
  757. k->p += VtEntrySize;
  758. }
  759. void
  760. dirSinkWriteSink(DirSink *k, Sink *sink)
  761. {
  762. dirSinkWrite(k, &sink->dir);
  763. }
  764. int
  765. dirSinkWriteFile(DirSink *k, VacFile *vf)
  766. {
  767. VtEntry dir;
  768. if(!vfGetVtEntry(vf, &dir))
  769. return 0;
  770. dirSinkWrite(k, &dir);
  771. return 1;
  772. }
  773. void
  774. dirSinkClose(DirSink *k)
  775. {
  776. metaSinkClose(k->msink);
  777. if(k->p != k->buf)
  778. sinkWrite(k->sink, k->buf, k->p - k->buf);
  779. sinkClose(k->sink);
  780. }
  781. void
  782. dirSinkFree(DirSink *k)
  783. {
  784. sinkFree(k->sink);
  785. metaSinkFree(k->msink);
  786. vtMemFree(k->buf);
  787. vtMemFree(k);
  788. }
  789. MetaSink *
  790. metaSinkAlloc(VtSession *z, int psize, int dsize)
  791. {
  792. MetaSink *k;
  793. k = vtMemAllocZ(sizeof(MetaSink));
  794. k->sink = sinkAlloc(z, psize, dsize);
  795. k->buf = vtMemAlloc(dsize);
  796. k->maxindex = dsize/100; /* 100 byte entries seems reasonable */
  797. if(k->maxindex < 1)
  798. k->maxindex = 1;
  799. k->rp = k->p = k->buf + MetaHeaderSize + k->maxindex*MetaIndexSize;
  800. k->ep = k->buf + dsize;
  801. return k;
  802. }
  803. /* hack to get base to compare routine - not reentrant */
  804. uchar *blockBase;
  805. int
  806. dirCmp(void *p0, void *p1)
  807. {
  808. uchar *q0, *q1;
  809. int n0, n1, r;
  810. /* name is first element of entry */
  811. q0 = p0;
  812. q0 = blockBase + (q0[0]<<8) + q0[1];
  813. n0 = (q0[6]<<8) + q0[7];
  814. q0 += 8;
  815. q1 = p1;
  816. q1 = blockBase + (q1[0]<<8) + q1[1];
  817. n1 = (q1[6]<<8) + q1[7];
  818. q1 += 8;
  819. if(n0 == n1)
  820. return memcmp(q0, q1, n0);
  821. else if (n0 < n1) {
  822. r = memcmp(q0, q1, n0);
  823. return (r==0)?1:r;
  824. } else {
  825. r = memcmp(q0, q1, n1);
  826. return (r==0)?-1:r;
  827. }
  828. }
  829. void
  830. metaSinkFlush(MetaSink *k)
  831. {
  832. uchar *p;
  833. int n;
  834. MetaBlock mb;
  835. if(k->nindex == 0)
  836. return;
  837. assert(k->nindex <= k->maxindex);
  838. p = k->buf;
  839. n = k->rp - p;
  840. mb.size = n;
  841. mb.free = 0;
  842. mb.nindex = k->nindex;
  843. mb.maxindex = k->maxindex;
  844. mb.buf = p;
  845. mbPack(&mb);
  846. p += MetaHeaderSize;
  847. /* XXX this is not reentrant! */
  848. blockBase = k->buf;
  849. qsort(p, k->nindex, MetaIndexSize, dirCmp);
  850. p += k->nindex*MetaIndexSize;
  851. memset(p, 0, (k->maxindex-k->nindex)*MetaIndexSize);
  852. p += (k->maxindex-k->nindex)*MetaIndexSize;
  853. sinkWrite(k->sink, k->buf, n);
  854. /* move down partial entry */
  855. n = k->p - k->rp;
  856. memmove(p, k->rp, n);
  857. k->rp = p;
  858. k->p = p + n;
  859. k->nindex = 0;
  860. }
  861. void
  862. metaSinkPutc(MetaSink *k, int c)
  863. {
  864. if(k->p+1 > k->ep)
  865. metaSinkFlush(k);
  866. if(k->p+1 > k->ep)
  867. vtFatal("directory entry too large");
  868. k->p[0] = c;
  869. k->p++;
  870. }
  871. void
  872. metaSinkPutString(MetaSink *k, char *s)
  873. {
  874. int n = strlen(s);
  875. metaSinkPutc(k, n>>8);
  876. metaSinkPutc(k, n);
  877. metaSinkWrite(k, (uchar*)s, n);
  878. }
  879. void
  880. metaSinkPutUint32(MetaSink *k, ulong x)
  881. {
  882. metaSinkPutc(k, x>>24);
  883. metaSinkPutc(k, x>>16);
  884. metaSinkPutc(k, x>>8);
  885. metaSinkPutc(k, x);
  886. }
  887. void
  888. metaSinkPutUint64(MetaSink *k, uvlong x)
  889. {
  890. metaSinkPutUint32(k, x>>32);
  891. metaSinkPutUint32(k, x);
  892. }
  893. void
  894. metaSinkWrite(MetaSink *k, uchar *data, int n)
  895. {
  896. if(k->p + n > k->ep)
  897. metaSinkFlush(k);
  898. if(k->p + n > k->ep)
  899. vtFatal("directory entry too large");
  900. memmove(k->p, data, n);
  901. k->p += n;
  902. }
  903. void
  904. metaSinkWriteDir(MetaSink *ms, VacDir *dir)
  905. {
  906. metaSinkPutUint32(ms, DirMagic);
  907. metaSinkPutc(ms, Version>>8);
  908. metaSinkPutc(ms, Version);
  909. metaSinkPutString(ms, dir->elem);
  910. metaSinkPutUint32(ms, dir->entry);
  911. metaSinkPutUint64(ms, dir->qid);
  912. metaSinkPutString(ms, dir->uid);
  913. metaSinkPutString(ms, dir->gid);
  914. metaSinkPutString(ms, dir->mid);
  915. metaSinkPutUint32(ms, dir->mtime);
  916. metaSinkPutUint32(ms, dir->mcount);
  917. metaSinkPutUint32(ms, dir->ctime);
  918. metaSinkPutUint32(ms, dir->atime);
  919. metaSinkPutUint32(ms, dir->mode);
  920. if(dir->plan9) {
  921. metaSinkPutc(ms, DirPlan9Entry); /* plan9 extra info */
  922. metaSinkPutc(ms, 0); /* plan9 extra size */
  923. metaSinkPutc(ms, 12); /* plan9 extra size */
  924. metaSinkPutUint64(ms, dir->p9path);
  925. metaSinkPutUint32(ms, dir->p9version);
  926. }
  927. if(dir->qidSpace != 0) {
  928. metaSinkPutc(ms, DirQidSpaceEntry);
  929. metaSinkPutc(ms, 0);
  930. metaSinkPutc(ms, 16);
  931. metaSinkPutUint64(ms, dir->qidOffset);
  932. metaSinkPutUint64(ms, dir->qidMax);
  933. }
  934. if(dir->gen != 0) {
  935. metaSinkPutc(ms, DirGenEntry);
  936. metaSinkPutc(ms, 0);
  937. metaSinkPutc(ms, 4);
  938. metaSinkPutUint32(ms, dir->gen);
  939. }
  940. metaSinkEOR(ms);
  941. }
  942. void
  943. plan9ToVacDir(VacDir *vd, Dir *dir, ulong entry, uvlong qid)
  944. {
  945. memset(vd, 0, sizeof(VacDir));
  946. vd->elem = vtStrDup(dir->name);
  947. vd->entry = entry;
  948. vd->qid = qid;
  949. vd->uid = vtStrDup(dir->uid);
  950. vd->gid = vtStrDup(dir->gid);
  951. vd->mid = vtStrDup(dir->muid);
  952. vd->mtime = dir->mtime;
  953. vd->mcount = 0;
  954. vd->ctime = dir->mtime; /* ctime: not available on plan 9 */
  955. vd->atime = dir->atime;
  956. vd->mode = dir->mode & 0777;
  957. if(dir->mode & DMDIR)
  958. vd->mode |= ModeDir;
  959. if(dir->mode & DMAPPEND)
  960. vd->mode |= ModeAppend;
  961. if(dir->mode & DMEXCL)
  962. vd->mode |= ModeExclusive;
  963. vd->plan9 = 1;
  964. vd->p9path = dir->qid.path;
  965. vd->p9version = dir->qid.vers;
  966. }
  967. void
  968. metaSinkEOR(MetaSink *k)
  969. {
  970. uchar *p;
  971. int o, n;
  972. p = k->buf + MetaHeaderSize;
  973. p += k->nindex * MetaIndexSize;
  974. o = k->rp-k->buf; /* offset from start of block */
  975. n = k->p-k->rp; /* size of entry */
  976. p[0] = o >> 8;
  977. p[1] = o;
  978. p[2] = n >> 8;
  979. p[3] = n;
  980. k->rp = k->p;
  981. k->nindex++;
  982. if(k->nindex == k->maxindex)
  983. metaSinkFlush(k);
  984. }
  985. void
  986. metaSinkClose(MetaSink *k)
  987. {
  988. metaSinkFlush(k);
  989. sinkClose(k->sink);
  990. }
  991. void
  992. metaSinkFree(MetaSink *k)
  993. {
  994. sinkFree(k->sink);
  995. vtMemFree(k->buf);
  996. vtMemFree(k);
  997. }
  998. static void
  999. warn(char *fmt, ...)
  1000. {
  1001. va_list arg;
  1002. va_start(arg, fmt);
  1003. fprint(2, "%s: ", argv0);
  1004. vfprint(2, fmt, arg);
  1005. fprint(2, "\n");
  1006. va_end(arg);
  1007. }
  1008. static void
  1009. cleanup(void)
  1010. {
  1011. if(oname != nil)
  1012. remove(oname);
  1013. }
  1014. #define TWID64 ((u64int)~(u64int)0)
  1015. static u64int
  1016. unittoull(char *s)
  1017. {
  1018. char *es;
  1019. u64int n;
  1020. if(s == nil)
  1021. return TWID64;
  1022. n = strtoul(s, &es, 0);
  1023. if(*es == 'k' || *es == 'K'){
  1024. n *= 1024;
  1025. es++;
  1026. }else if(*es == 'm' || *es == 'M'){
  1027. n *= 1024*1024;
  1028. es++;
  1029. }else if(*es == 'g' || *es == 'G'){
  1030. n *= 1024*1024*1024;
  1031. es++;
  1032. }
  1033. if(*es != '\0')
  1034. return TWID64;
  1035. return n;
  1036. }