flfmt.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. #include "stdinc.h"
  2. #include "dat.h"
  3. #include "fns.h"
  4. #define blockWrite _blockWrite /* hack */
  5. static void usage(void);
  6. static u64int fdsize(int fd);
  7. static void partition(int fd, int bsize, Header *h);
  8. static void writeBlock(int fd, uchar *buf, int bsize, ulong bn);
  9. static u64int unittoull(char *s);
  10. static u32int blockAlloc(int type, u32int tag);
  11. static void blockRead(int part, u32int addr);
  12. static void blockWrite(int part, u32int addr);
  13. static void superInit(char *label, u32int root);
  14. static void rootMetaInit(Entry *e);
  15. static u32int rootInit(Entry *e);
  16. static void topLevel(char *name);
  17. static int parseScore(uchar[VtScoreSize], char*);
  18. static u32int ventiRoot(char*, char*);
  19. static VtSession *z;
  20. #define TWID64 ((u64int)~(u64int)0)
  21. Disk *disk;
  22. Fs *fs;
  23. uchar *buf;
  24. int bsize = 8*1024;
  25. u64int qid = 1;
  26. int
  27. confirm(char *msg)
  28. {
  29. char buf[100];
  30. int n;
  31. fprint(2, "%s [y/n]: ", msg);
  32. n = read(0, buf, sizeof buf - 1);
  33. if(n <= 0)
  34. return 0;
  35. if(buf[0] == 'y')
  36. return 1;
  37. return 0;
  38. }
  39. void
  40. main(int argc, char *argv[])
  41. {
  42. int fd, force;
  43. Header h;
  44. ulong bn;
  45. Entry e;
  46. char *label = "vfs";
  47. char *host = nil;
  48. char *score = nil;
  49. u32int root;
  50. Dir *d;
  51. force = 0;
  52. ARGBEGIN{
  53. default:
  54. usage();
  55. case 'b':
  56. bsize = unittoull(EARGF(usage()));
  57. if(bsize == ~0)
  58. usage();
  59. break;
  60. case 'h':
  61. host = EARGF(usage());
  62. break;
  63. case 'l':
  64. label = EARGF(usage());
  65. break;
  66. case 'v':
  67. score = EARGF(usage());
  68. break;
  69. /*
  70. * This is -y instead of -f because flchk has a
  71. * (frequently used) -f option. I type flfmt instead
  72. * of flchk all the time, and want to make it hard
  73. * to reformat my file system accidentally.
  74. */
  75. case 'y':
  76. force = 1;
  77. break;
  78. }ARGEND
  79. if(argc != 1)
  80. usage();
  81. vtAttach();
  82. fmtinstall('V', scoreFmt);
  83. fmtinstall('R', vtErrFmt);
  84. fmtinstall('L', labelFmt);
  85. fd = open(argv[0], ORDWR);
  86. if(fd < 0)
  87. vtFatal("could not open file: %s: %r", argv[0]);
  88. buf = vtMemAllocZ(bsize);
  89. if(pread(fd, buf, bsize, HeaderOffset) != bsize)
  90. vtFatal("could not read fs header block: %r");
  91. if(headerUnpack(&h, buf) && !force
  92. && !confirm("fs header block already exists; are you sure?"))
  93. goto Out;
  94. if((d = dirfstat(fd)) == nil)
  95. vtFatal("dirfstat: %r");
  96. if(d->type == 'M' && !force
  97. && !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?"))
  98. goto Out;
  99. partition(fd, bsize, &h);
  100. headerPack(&h, buf);
  101. if(pwrite(fd, buf, bsize, HeaderOffset) < bsize)
  102. vtFatal("could not write fs header: %r");
  103. disk = diskAlloc(fd);
  104. if(disk == nil)
  105. vtFatal("could not open disk: %r");
  106. /* zero labels */
  107. memset(buf, 0, bsize);
  108. for(bn = 0; bn < diskSize(disk, PartLabel); bn++)
  109. blockWrite(PartLabel, bn);
  110. if(score)
  111. root = ventiRoot(host, score);
  112. else{
  113. rootMetaInit(&e);
  114. root = rootInit(&e);
  115. }
  116. superInit(label, root);
  117. diskFree(disk);
  118. if(score == nil)
  119. topLevel(argv[0]);
  120. Out:
  121. vtDetach();
  122. exits(0);
  123. }
  124. static u64int
  125. fdsize(int fd)
  126. {
  127. Dir *dir;
  128. u64int size;
  129. dir = dirfstat(fd);
  130. if(dir == nil)
  131. vtFatal("could not stat file: %r");
  132. size = dir->length;
  133. free(dir);
  134. return size;
  135. }
  136. static void
  137. usage(void)
  138. {
  139. fprint(2, "usage: %s [-b blocksize] [-h host] [-l label] [-v score] [-y] file\n", argv0);
  140. exits("usage");
  141. }
  142. static void
  143. partition(int fd, int bsize, Header *h)
  144. {
  145. ulong nblock, ndata, nlabel;
  146. ulong lpb;
  147. if(bsize % 512 != 0)
  148. sysfatal("block size must be a multiple of 512 bytes");
  149. if(bsize > VtMaxLumpSize)
  150. sysfatal("block size must be less than %d", VtMaxLumpSize);
  151. memset(h, 0, sizeof(*h));
  152. h->blockSize = bsize;
  153. lpb = bsize/LabelSize;
  154. nblock = fdsize(fd)/bsize;
  155. /* sanity check */
  156. if(nblock < (HeaderOffset*10)/bsize)
  157. vtFatal("file too small");
  158. h->super = (HeaderOffset + 2*bsize)/bsize;
  159. h->label = h->super + 1;
  160. ndata = ((u64int)lpb)*(nblock - h->label)/(lpb+1);
  161. nlabel = (ndata + lpb - 1)/lpb;
  162. h->data = h->label + nlabel;
  163. h->end = h->data + ndata;
  164. assert(h->end == nblock);
  165. }
  166. static u32int
  167. tagGen(void)
  168. {
  169. u32int tag;
  170. for(;;){
  171. tag = lrand();
  172. if(tag > RootTag)
  173. break;
  174. }
  175. return tag;
  176. }
  177. static void
  178. entryInit(Entry *e)
  179. {
  180. e->gen = 0;
  181. e->dsize = bsize;
  182. e->psize = bsize/VtEntrySize*VtEntrySize;
  183. e->flags = VtEntryActive;
  184. e->depth = 0;
  185. e->size = 0;
  186. memmove(e->score, vtZeroScore, VtScoreSize);
  187. e->tag = tagGen();
  188. e->snap = 0;
  189. e->archive = 0;
  190. }
  191. static void
  192. rootMetaInit(Entry *e)
  193. {
  194. u32int addr;
  195. u32int tag;
  196. DirEntry de;
  197. MetaBlock mb;
  198. MetaEntry me;
  199. memset(&de, 0, sizeof(de));
  200. de.elem = vtStrDup("root");
  201. de.entry = 0;
  202. de.gen = 0;
  203. de.mentry = 1;
  204. de.mgen = 0;
  205. de.size = 0;
  206. de.qid = qid++;
  207. de.uid = vtStrDup("adm");
  208. de.gid = vtStrDup("adm");
  209. de.mid = vtStrDup("adm");
  210. de.mtime = time(0);
  211. de.mcount = 0;
  212. de.ctime = time(0);
  213. de.atime = time(0);
  214. de.mode = ModeDir | 0555;
  215. tag = tagGen();
  216. addr = blockAlloc(BtData, tag);
  217. /* build up meta block */
  218. memset(buf, 0, bsize);
  219. mbInit(&mb, buf, bsize, bsize/100);
  220. me.size = deSize(&de);
  221. me.p = mbAlloc(&mb, me.size);
  222. assert(me.p != nil);
  223. dePack(&de, &me);
  224. mbInsert(&mb, 0, &me);
  225. mbPack(&mb);
  226. blockWrite(PartData, addr);
  227. deCleanup(&de);
  228. /* build up entry for meta block */
  229. entryInit(e);
  230. e->flags |= VtEntryLocal;
  231. e->size = bsize;
  232. e->tag = tag;
  233. localToGlobal(addr, e->score);
  234. }
  235. static u32int
  236. rootInit(Entry *e)
  237. {
  238. ulong addr;
  239. u32int tag;
  240. tag = tagGen();
  241. addr = blockAlloc(BtDir, tag);
  242. memset(buf, 0, bsize);
  243. /* root meta data is in the third entry */
  244. entryPack(e, buf, 2);
  245. entryInit(e);
  246. e->flags |= VtEntryDir;
  247. entryPack(e, buf, 0);
  248. entryInit(e);
  249. entryPack(e, buf, 1);
  250. blockWrite(PartData, addr);
  251. entryInit(e);
  252. e->flags |= VtEntryLocal|VtEntryDir;
  253. e->size = VtEntrySize*3;
  254. e->tag = tag;
  255. localToGlobal(addr, e->score);
  256. addr = blockAlloc(BtDir, RootTag);
  257. memset(buf, 0, bsize);
  258. entryPack(e, buf, 0);
  259. blockWrite(PartData, addr);
  260. return addr;
  261. }
  262. static u32int
  263. blockAlloc(int type, u32int tag)
  264. {
  265. static u32int addr;
  266. Label l;
  267. int lpb;
  268. lpb = bsize/LabelSize;
  269. blockRead(PartLabel, addr/lpb);
  270. if(!labelUnpack(&l, buf, addr % lpb) || l.state != BsFree)
  271. vtFatal("bad label: %r");
  272. l.epoch = 1;
  273. l.epochClose = ~(u32int)0;
  274. l.type = type;
  275. l.state = BsAlloc;
  276. l.tag = tag;
  277. labelPack(&l, buf, addr % lpb);
  278. blockWrite(PartLabel, addr/lpb);
  279. return addr++;
  280. }
  281. static void
  282. superInit(char *label, u32int root)
  283. {
  284. Super s;
  285. memset(buf, 0, bsize);
  286. memset(&s, 0, sizeof(s));
  287. s.version = SuperVersion;
  288. s.epochLow = 1;
  289. s.epochHigh = 1;
  290. s.qid = qid;
  291. s.active = root;
  292. s.next = NilBlock;
  293. s.current = NilBlock;
  294. strecpy(s.name, s.name+sizeof(s.name), label);
  295. memmove(s.last, vtZeroScore, VtScoreSize);
  296. superPack(&s, buf);
  297. blockWrite(PartSuper, 0);
  298. }
  299. static u64int
  300. unittoull(char *s)
  301. {
  302. char *es;
  303. u64int n;
  304. if(s == nil)
  305. return TWID64;
  306. n = strtoul(s, &es, 0);
  307. if(*es == 'k' || *es == 'K'){
  308. n *= 1024;
  309. es++;
  310. }else if(*es == 'm' || *es == 'M'){
  311. n *= 1024*1024;
  312. es++;
  313. }else if(*es == 'g' || *es == 'G'){
  314. n *= 1024*1024*1024;
  315. es++;
  316. }
  317. if(*es != '\0')
  318. return TWID64;
  319. return n;
  320. }
  321. static void
  322. blockRead(int part, u32int addr)
  323. {
  324. if(!diskReadRaw(disk, part, addr, buf))
  325. vtFatal("read failed: %r");
  326. }
  327. static void
  328. blockWrite(int part, u32int addr)
  329. {
  330. if(!diskWriteRaw(disk, part, addr, buf))
  331. vtFatal("write failed: %r");
  332. }
  333. static void
  334. addFile(File *root, char *name, uint mode)
  335. {
  336. File *f;
  337. f = fileCreate(root, name, mode | ModeDir, "adm");
  338. if(f == nil)
  339. vtFatal("could not create file: %s: %r", name);
  340. fileDecRef(f);
  341. }
  342. static void
  343. topLevel(char *name)
  344. {
  345. Fs *fs;
  346. File *root;
  347. /* ok, now we can open as a fs */
  348. fs = fsOpen(name, z, 100, OReadWrite);
  349. if(fs == nil)
  350. vtFatal("could not open file system: %r");
  351. vtRLock(fs->elk);
  352. root = fsGetRoot(fs);
  353. if(root == nil)
  354. vtFatal("could not open root: %r");
  355. addFile(root, "active", 0777); /* BUG: add create command to Ccmd instead */
  356. addFile(root, "archive", 0555);
  357. addFile(root, "snapshot", 0555);
  358. fileDecRef(root);
  359. vtRUnlock(fs->elk);
  360. fsClose(fs);
  361. }
  362. static int
  363. ventiRead(uchar score[VtScoreSize], int type)
  364. {
  365. int n;
  366. n = vtRead(z, score, type, buf, bsize);
  367. if(n < 0)
  368. vtFatal("ventiRead %V (%d) failed: %R", score, type);
  369. vtZeroExtend(type, buf, n, bsize);
  370. return n;
  371. }
  372. static u32int
  373. ventiRoot(char *host, char *s)
  374. {
  375. int i, n;
  376. uchar score[VtScoreSize];
  377. u32int addr, tag;
  378. DirEntry de;
  379. MetaBlock mb;
  380. MetaEntry me;
  381. Entry e;
  382. VtRoot root;
  383. if(!parseScore(score, s))
  384. vtFatal("bad score '%s'", s);
  385. if((z = vtDial(host, 0)) == nil
  386. || !vtConnect(z, nil))
  387. vtFatal("connect to venti: %R");
  388. tag = tagGen();
  389. addr = blockAlloc(BtDir, tag);
  390. ventiRead(score, VtRootType);
  391. if(!vtRootUnpack(&root, buf))
  392. vtFatal("corrupted root: vtRootUnpack");
  393. n = ventiRead(root.score, VtDirType);
  394. /*
  395. * Fossil's vac archives start with an extra layer of source,
  396. * but vac's don't.
  397. */
  398. if(n <= 2*VtEntrySize){
  399. if(!entryUnpack(&e, buf, 0))
  400. vtFatal("bad root: top entry");
  401. n = ventiRead(e.score, VtDirType);
  402. }
  403. /*
  404. * There should be three root sources (and nothing else) here.
  405. */
  406. for(i=0; i<3; i++){
  407. if(!entryUnpack(&e, buf, i)
  408. || !(e.flags&VtEntryActive)
  409. || e.psize < 256
  410. || e.dsize < 256)
  411. vtFatal("bad root: entry %d", i);
  412. fprint(2, "%V\n", e.score);
  413. }
  414. if(n > 3*VtEntrySize)
  415. vtFatal("bad root: entry count");
  416. blockWrite(PartData, addr);
  417. /*
  418. * Maximum qid is recorded in root's msource, entry #2 (conveniently in e).
  419. */
  420. ventiRead(e.score, VtDataType);
  421. if(!mbUnpack(&mb, buf, bsize))
  422. vtFatal("bad root: mbUnpack");
  423. meUnpack(&me, &mb, 0);
  424. if(!deUnpack(&de, &me))
  425. vtFatal("bad root: dirUnpack");
  426. if(!de.qidSpace)
  427. vtFatal("bad root: no qidSpace");
  428. qid = de.qidMax;
  429. /*
  430. * Recreate the top layer of source.
  431. */
  432. entryInit(&e);
  433. e.flags |= VtEntryLocal|VtEntryDir;
  434. e.size = VtEntrySize*3;
  435. e.tag = tag;
  436. localToGlobal(addr, e.score);
  437. addr = blockAlloc(BtDir, RootTag);
  438. memset(buf, 0, bsize);
  439. entryPack(&e, buf, 0);
  440. blockWrite(PartData, addr);
  441. return addr;
  442. }
  443. static int
  444. parseScore(uchar *score, char *buf)
  445. {
  446. int i, c;
  447. memset(score, 0, VtScoreSize);
  448. if(strlen(buf) < VtScoreSize*2)
  449. return 0;
  450. for(i=0; i<VtScoreSize*2; i++){
  451. if(buf[i] >= '0' && buf[i] <= '9')
  452. c = buf[i] - '0';
  453. else if(buf[i] >= 'a' && buf[i] <= 'f')
  454. c = buf[i] - 'a' + 10;
  455. else if(buf[i] >= 'A' && buf[i] <= 'F')
  456. c = buf[i] - 'A' + 10;
  457. else
  458. return 0;
  459. if((i & 1) == 0)
  460. c <<= 4;
  461. score[i>>1] |= c;
  462. }
  463. return 1;
  464. }