flfmt.c 11 KB

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