flfmt.c 11 KB

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