Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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