vac.c 23 KB

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