plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

flfmt.c (10680B)


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