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