flfmt.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  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, uchar[VtScoreSize]);
  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, vtZeroScore);
  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. }
  165. static u32int
  166. tagGen(void)
  167. {
  168. u32int tag;
  169. for(;;){
  170. tag = lrand();
  171. if(tag > RootTag)
  172. break;
  173. }
  174. return tag;
  175. }
  176. static void
  177. entryInit(Entry *e)
  178. {
  179. e->gen = 0;
  180. e->dsize = bsize;
  181. e->psize = bsize/VtEntrySize*VtEntrySize;
  182. e->flags = VtEntryActive;
  183. e->depth = 0;
  184. e->size = 0;
  185. memmove(e->score, vtZeroScore, VtScoreSize);
  186. e->tag = tagGen();
  187. e->snap = 0;
  188. e->archive = 0;
  189. }
  190. static void
  191. rootMetaInit(Entry *e)
  192. {
  193. u32int addr;
  194. u32int tag;
  195. DirEntry de;
  196. MetaBlock mb;
  197. MetaEntry me;
  198. memset(&de, 0, sizeof(de));
  199. de.elem = vtStrDup("root");
  200. de.entry = 0;
  201. de.gen = 0;
  202. de.mentry = 1;
  203. de.mgen = 0;
  204. de.size = 0;
  205. de.qid = qid++;
  206. de.uid = vtStrDup("adm");
  207. de.gid = vtStrDup("adm");
  208. de.mid = vtStrDup("adm");
  209. de.mtime = time(0);
  210. de.mcount = 0;
  211. de.ctime = time(0);
  212. de.atime = time(0);
  213. de.mode = ModeDir | 0555;
  214. tag = tagGen();
  215. addr = blockAlloc(BtData, tag);
  216. /* build up meta block */
  217. memset(buf, 0, bsize);
  218. mbInit(&mb, buf, bsize, bsize/100);
  219. me.size = deSize(&de);
  220. me.p = mbAlloc(&mb, me.size);
  221. assert(me.p != nil);
  222. dePack(&de, &me);
  223. mbInsert(&mb, 0, &me);
  224. mbPack(&mb);
  225. blockWrite(PartData, addr);
  226. deCleanup(&de);
  227. /* build up entry for meta block */
  228. entryInit(e);
  229. e->flags |= VtEntryLocal;
  230. e->size = bsize;
  231. e->tag = tag;
  232. localToGlobal(addr, e->score);
  233. }
  234. static u32int
  235. rootInit(Entry *e)
  236. {
  237. ulong addr;
  238. u32int tag;
  239. tag = tagGen();
  240. addr = blockAlloc(BtDir, tag);
  241. memset(buf, 0, bsize);
  242. /* root meta data is in the third entry */
  243. entryPack(e, buf, 2);
  244. entryInit(e);
  245. e->flags |= VtEntryDir;
  246. entryPack(e, buf, 0);
  247. entryInit(e);
  248. entryPack(e, buf, 1);
  249. blockWrite(PartData, addr);
  250. entryInit(e);
  251. e->flags |= VtEntryLocal|VtEntryDir;
  252. e->size = VtEntrySize*3;
  253. e->tag = tag;
  254. localToGlobal(addr, e->score);
  255. addr = blockAlloc(BtDir, RootTag);
  256. memset(buf, 0, bsize);
  257. entryPack(e, buf, 0);
  258. blockWrite(PartData, addr);
  259. return addr;
  260. }
  261. static u32int
  262. blockAlloc(int type, u32int tag)
  263. {
  264. static u32int addr;
  265. Label l;
  266. int lpb;
  267. lpb = bsize/LabelSize;
  268. blockRead(PartLabel, addr/lpb);
  269. if(!labelUnpack(&l, buf, addr % lpb) || l.state != BsFree)
  270. vtFatal("bad label: %r");
  271. l.epoch = 1;
  272. l.epochClose = ~(u32int)0;
  273. l.type = type;
  274. l.state = BsAlloc;
  275. l.tag = tag;
  276. labelPack(&l, buf, addr % lpb);
  277. blockWrite(PartLabel, addr/lpb);
  278. return addr++;
  279. }
  280. static void
  281. superInit(char *label, u32int root, uchar score[VtScoreSize])
  282. {
  283. Super s;
  284. memset(buf, 0, bsize);
  285. memset(&s, 0, sizeof(s));
  286. s.version = SuperVersion;
  287. s.epochLow = 1;
  288. s.epochHigh = 1;
  289. s.qid = qid;
  290. s.active = root;
  291. s.next = NilBlock;
  292. s.current = NilBlock;
  293. strecpy(s.name, s.name+sizeof(s.name), label);
  294. memmove(s.last, score, VtScoreSize);
  295. superPack(&s, buf);
  296. blockWrite(PartSuper, 0);
  297. }
  298. static u64int
  299. unittoull(char *s)
  300. {
  301. char *es;
  302. u64int n;
  303. if(s == nil)
  304. return TWID64;
  305. n = strtoul(s, &es, 0);
  306. if(*es == 'k' || *es == 'K'){
  307. n *= 1024;
  308. es++;
  309. }else if(*es == 'm' || *es == 'M'){
  310. n *= 1024*1024;
  311. es++;
  312. }else if(*es == 'g' || *es == 'G'){
  313. n *= 1024*1024*1024;
  314. es++;
  315. }
  316. if(*es != '\0')
  317. return TWID64;
  318. return n;
  319. }
  320. static void
  321. blockRead(int part, u32int addr)
  322. {
  323. if(!diskReadRaw(disk, part, addr, buf))
  324. vtFatal("read failed: %r");
  325. }
  326. static void
  327. blockWrite(int part, u32int addr)
  328. {
  329. if(!diskWriteRaw(disk, part, addr, buf))
  330. vtFatal("write failed: %r");
  331. }
  332. static void
  333. addFile(File *root, char *name, uint mode)
  334. {
  335. File *f;
  336. f = fileCreate(root, name, mode | ModeDir, "adm");
  337. if(f == nil)
  338. vtFatal("could not create file: %s: %r", name);
  339. fileDecRef(f);
  340. }
  341. static void
  342. topLevel(char *name)
  343. {
  344. Fs *fs;
  345. File *root;
  346. /* ok, now we can open as a fs */
  347. fs = fsOpen(name, z, 100, OReadWrite);
  348. if(fs == nil)
  349. vtFatal("could not open file system: %r");
  350. vtRLock(fs->elk);
  351. root = fsGetRoot(fs);
  352. if(root == nil)
  353. vtFatal("could not open root: %r");
  354. addFile(root, "active", 0777); /* BUG: add create command to Ccmd instead */
  355. addFile(root, "archive", 0555);
  356. addFile(root, "snapshot", 0555);
  357. fileDecRef(root);
  358. vtRUnlock(fs->elk);
  359. fsClose(fs);
  360. }
  361. static int
  362. ventiRead(uchar score[VtScoreSize], int type)
  363. {
  364. int n;
  365. n = vtRead(z, score, type, buf, bsize);
  366. if(n < 0)
  367. vtFatal("ventiRead %V (%d) failed: %R", score, type);
  368. vtZeroExtend(type, buf, n, bsize);
  369. return n;
  370. }
  371. static u32int
  372. ventiRoot(char *host, char *s)
  373. {
  374. int i, n;
  375. uchar score[VtScoreSize];
  376. u32int addr, tag;
  377. DirEntry de;
  378. MetaBlock mb;
  379. MetaEntry me;
  380. Entry e;
  381. VtRoot root;
  382. if(!parseScore(score, s))
  383. vtFatal("bad score '%s'", s);
  384. if((z = vtDial(host, 0)) == nil
  385. || !vtConnect(z, nil))
  386. vtFatal("connect to venti: %R");
  387. tag = tagGen();
  388. addr = blockAlloc(BtDir, tag);
  389. ventiRead(score, VtRootType);
  390. if(!vtRootUnpack(&root, buf))
  391. vtFatal("corrupted root: vtRootUnpack");
  392. n = ventiRead(root.score, VtDirType);
  393. /*
  394. * Fossil's vac archives start with an extra layer of source,
  395. * but vac's don't.
  396. */
  397. if(n <= 2*VtEntrySize){
  398. if(!entryUnpack(&e, buf, 0))
  399. vtFatal("bad root: top entry");
  400. n = ventiRead(e.score, VtDirType);
  401. }
  402. /*
  403. * There should be three root sources (and nothing else) here.
  404. */
  405. for(i=0; i<3; i++){
  406. if(!entryUnpack(&e, buf, i)
  407. || !(e.flags&VtEntryActive)
  408. || e.psize < 256
  409. || e.dsize < 256)
  410. vtFatal("bad root: entry %d", i);
  411. fprint(2, "%V\n", e.score);
  412. }
  413. if(n > 3*VtEntrySize)
  414. vtFatal("bad root: entry count");
  415. blockWrite(PartData, addr);
  416. /*
  417. * Maximum qid is recorded in root's msource, entry #2 (conveniently in e).
  418. */
  419. ventiRead(e.score, VtDataType);
  420. if(!mbUnpack(&mb, buf, bsize))
  421. vtFatal("bad root: mbUnpack");
  422. meUnpack(&me, &mb, 0);
  423. if(!deUnpack(&de, &me))
  424. vtFatal("bad root: dirUnpack");
  425. if(!de.qidSpace)
  426. vtFatal("bad root: no qidSpace");
  427. qid = de.qidMax;
  428. /*
  429. * Recreate the top layer of source.
  430. */
  431. entryInit(&e);
  432. e.flags |= VtEntryLocal|VtEntryDir;
  433. e.size = VtEntrySize*3;
  434. e.tag = tag;
  435. localToGlobal(addr, e.score);
  436. addr = blockAlloc(BtDir, RootTag);
  437. memset(buf, 0, bsize);
  438. entryPack(&e, buf, 0);
  439. blockWrite(PartData, addr);
  440. return addr;
  441. }
  442. static int
  443. parseScore(uchar *score, char *buf)
  444. {
  445. int i, c;
  446. memset(score, 0, VtScoreSize);
  447. if(strlen(buf) < VtScoreSize*2)
  448. return 0;
  449. for(i=0; i<VtScoreSize*2; i++){
  450. if(buf[i] >= '0' && buf[i] <= '9')
  451. c = buf[i] - '0';
  452. else if(buf[i] >= 'a' && buf[i] <= 'f')
  453. c = buf[i] - 'a' + 10;
  454. else if(buf[i] >= 'A' && buf[i] <= 'F')
  455. c = buf[i] - 'A' + 10;
  456. else
  457. return 0;
  458. if((i & 1) == 0)
  459. c <<= 4;
  460. score[i>>1] |= c;
  461. }
  462. return 1;
  463. }