Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Initialize a fossil file system from an ISO9660 image already in the
3
 * file system.  This is a fairly bizarre thing to do, but it lets us generate
4
 * installation CDs that double as valid Plan 9 disk partitions.  
5
 * People having trouble booting the CD can just copy it into a disk
6
 * partition and you've got a working Plan 9 system.
7
 *
8
 * I've tried hard to keep all the associated cruft in this file.
9
 * If you deleted this file and cut out the three calls into it from flfmt.c,
10
 * no traces would remain.
11
 */
12
 
13
#include "stdinc.h"
14
#include "dat.h"
15
#include "fns.h"
16
#include "flfmt9660.h"
17
#include <bio.h>
18
#include <ctype.h>
19
 
20
static Biobuf *b;
21
 
22
enum{
23
	Tag = 0x96609660,
24
	Blocksize = 2048,
25
};
26
 
27
#pragma varargck type "s" uchar*
28
#pragma varargck type "L" uchar*
29
#pragma varargck type "B" uchar*
30
#pragma varargck type "N" uchar*
31
#pragma varargck type "T" uchar*
32
#pragma varargck type "D" uchar*
33
 
34
typedef struct Voldesc Voldesc;
35
struct Voldesc {
36
	uchar	magic[8];	/* 0x01, "CD001", 0x01, 0x00 */
37
	uchar	systemid[32];	/* system identifier */
38
	uchar	volumeid[32];	/* volume identifier */
39
	uchar	unused[8];	/* character set in secondary desc */
40
	uchar	volsize[8];	/* volume size */
41
	uchar	charset[32];
42
	uchar	volsetsize[4];	/* volume set size = 1 */
43
	uchar	volseqnum[4];	/* volume sequence number = 1 */
44
	uchar	blocksize[4];	/* logical block size */
45
	uchar	pathsize[8];	/* path table size */
46
	uchar	lpathloc[4];	/* Lpath */
47
	uchar	olpathloc[4];	/* optional Lpath */
48
	uchar	mpathloc[4];	/* Mpath */
49
	uchar	ompathloc[4];	/* optional Mpath */
50
	uchar	rootdir[34];	/* root directory */
51
	uchar	volsetid[128];	/* volume set identifier */
52
	uchar	publisher[128];
53
	uchar	prepid[128];	/* data preparer identifier */
54
	uchar	applid[128];	/* application identifier */
55
	uchar	notice[37];	/* copyright notice file */
56
	uchar	abstract[37];	/* abstract file */
57
	uchar	biblio[37];	/* bibliographic file */
58
	uchar	cdate[17];	/* creation date */
59
	uchar	mdate[17];	/* modification date */
60
	uchar	xdate[17];	/* expiration date */
61
	uchar	edate[17];	/* effective date */
62
	uchar	fsvers;		/* file system version = 1 */
63
};
64
 
65
static void
66
dumpbootvol(void *a)
67
{
68
	Voldesc *v;
69
 
70
	v = a;
71
	print("magic %.2ux %.5s %.2ux %2ux\n",
72
		v->magic[0], v->magic+1, v->magic[6], v->magic[7]);
73
	if(v->magic[0] == 0xFF)
74
		return;
75
 
76
	print("system %.32T\n", v->systemid);
77
	print("volume %.32T\n", v->volumeid);
78
	print("volume size %.4N\n", v->volsize);
79
	print("charset %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
80
		v->charset[0], v->charset[1], v->charset[2], v->charset[3],
81
		v->charset[4], v->charset[5], v->charset[6], v->charset[7]);
82
	print("volume set size %.2N\n", v->volsetsize);
83
	print("volume sequence number %.2N\n", v->volseqnum);
84
	print("logical block size %.2N\n", v->blocksize);
85
	print("path size %.4L\n", v->pathsize);
86
	print("lpath loc %.4L\n", v->lpathloc);
87
	print("opt lpath loc %.4L\n", v->olpathloc);
88
	print("mpath loc %.4B\n", v->mpathloc);
89
	print("opt mpath loc %.4B\n", v->ompathloc);
90
	print("rootdir %D\n", v->rootdir);
91
	print("volume set identifier %.128T\n", v->volsetid);
92
	print("publisher %.128T\n", v->publisher);
93
	print("preparer %.128T\n", v->prepid);
94
	print("application %.128T\n", v->applid);
95
	print("notice %.37T\n", v->notice);
96
	print("abstract %.37T\n", v->abstract);
97
	print("biblio %.37T\n", v->biblio);
98
	print("creation date %.17s\n", v->cdate);
99
	print("modification date %.17s\n", v->mdate);
100
	print("expiration date %.17s\n", v->xdate);
101
	print("effective date %.17s\n", v->edate);
102
	print("fs version %d\n", v->fsvers);
103
}
104
 
105
typedef struct Cdir Cdir;
106
struct Cdir {
107
	uchar	len;
108
	uchar	xlen;
109
	uchar	dloc[8];
110
	uchar	dlen[8];
111
	uchar	date[7];
112
	uchar	flags;
113
	uchar	unitsize;
114
	uchar	gapsize;
115
	uchar	volseqnum[4];
116
	uchar	namelen;
117
	uchar	name[1];	/* chumminess */
118
};
119
#pragma varargck type "D" Cdir*
120
 
121
static int
122
Dfmt(Fmt *fmt)
123
{
124
	char buf[128];
125
	Cdir *c;
126
 
127
	c = va_arg(fmt->args, Cdir*);
128
	if(c->namelen == 1 && c->name[0] == '\0' || c->name[0] == '\001') {
129
		snprint(buf, sizeof buf, ".%s dloc %.4N dlen %.4N",
130
			c->name[0] ? "." : "", c->dloc, c->dlen);
131
	} else {
132
		snprint(buf, sizeof buf, "%.*T dloc %.4N dlen %.4N", c->namelen, c->name,
133
			c->dloc, c->dlen);
134
	}
135
	fmtstrcpy(fmt, buf);
136
	return 0;
137
}
138
 
139
char longc, shortc;
140
static void
141
bigend(void)
142
{
143
	longc = 'B';
144
}
145
 
146
static void
147
littleend(void)
148
{
149
	longc = 'L';
150
}
151
 
152
static ulong
153
big(void *a, int n)
154
{
155
	uchar *p;
156
	ulong v;
157
	int i;
158
 
159
	p = a;
160
	v = 0;
161
	for(i=0; i<n; i++)
162
		v = (v<<8) | *p++;
163
	return v;
164
}
165
 
166
static ulong
167
little(void *a, int n)
168
{
169
	uchar *p;
170
	ulong v;
171
	int i;
172
 
173
	p = a;
174
	v = 0;
175
	for(i=0; i<n; i++)
176
		v |= (*p++<<(i*8));
177
	return v;
178
}
179
 
180
/* numbers in big or little endian. */
181
static int
182
BLfmt(Fmt *fmt)
183
{
184
	ulong v;
185
	uchar *p;
186
	char buf[20];
187
 
188
	p = va_arg(fmt->args, uchar*);
189
 
190
	if(!(fmt->flags&FmtPrec)) {
191
		fmtstrcpy(fmt, "*BL*");
192
		return 0;
193
	}
194
 
195
	if(fmt->r == 'B')
196
		v = big(p, fmt->prec);
197
	else
198
		v = little(p, fmt->prec);
199
 
200
	sprint(buf, "0x%.*lux", fmt->prec*2, v);
201
	fmt->flags &= ~FmtPrec;
202
	fmtstrcpy(fmt, buf);
203
	return 0;
204
}
205
 
206
/* numbers in both little and big endian */
207
static int
208
Nfmt(Fmt *fmt)
209
{
210
	char buf[100];
211
	uchar *p;
212
 
213
	p = va_arg(fmt->args, uchar*);
214
 
215
	sprint(buf, "%.*L %.*B", fmt->prec, p, fmt->prec, p+fmt->prec);
216
	fmt->flags &= ~FmtPrec;
217
	fmtstrcpy(fmt, buf);
218
	return 0;
219
}
220
 
221
static int
222
asciiTfmt(Fmt *fmt)
223
{
224
	char *p, buf[256];
225
	int i;
226
 
227
	p = va_arg(fmt->args, char*);
228
	for(i=0; i<fmt->prec; i++)
229
		buf[i] = *p++;
230
	buf[i] = '\0';
231
	for(p=buf+strlen(buf); p>buf && p[-1]==' '; p--)
232
		;
233
	p[0] = '\0';
234
	fmt->flags &= ~FmtPrec;
235
	fmtstrcpy(fmt, buf);
236
	return 0;
237
}
238
 
239
static void
240
ascii(void)
241
{
242
	fmtinstall('T', asciiTfmt);
243
}
244
 
245
static int
246
runeTfmt(Fmt *fmt)
247
{
248
	Rune buf[256], *r;
249
	int i;
250
	uchar *p;
251
 
252
	p = va_arg(fmt->args, uchar*);
253
	for(i=0; i*2+2<=fmt->prec; i++, p+=2)
254
		buf[i] = (p[0]<<8)|p[1];
255
	buf[i] = L'\0';
256
	for(r=buf+i; r>buf && r[-1]==L' '; r--)
257
		;
258
	r[0] = L'\0';
259
	fmt->flags &= ~FmtPrec;
260
	return fmtprint(fmt, "%S", buf);
261
}
262
 
263
static void
264
getsect(uchar *buf, int n)
265
{
266
	if(Bseek(b, n*2048, 0) != n*2048 || Bread(b, buf, 2048) != 2048)
267
{
268
abort();
269
		sysfatal("reading block at %,d: %r", n*2048);
270
}
271
}
272
 
273
static Header *h;
274
static int fd;
275
static char *file9660;
276
static int off9660;
277
static ulong startoff;
278
static ulong endoff;
279
static ulong fsoff;
280
static uchar root[2048];
281
static Voldesc *v;
282
static ulong iso9660start(Cdir*);
283
static void iso9660copydir(Fs*, File*, Cdir*);
284
static void iso9660copyfile(Fs*, File*, Cdir*);
285
 
286
void
287
iso9660init(int xfd, Header *xh, char *xfile9660, int xoff9660)
288
{
289
	uchar sect[2048], sect2[2048];
290
 
291
	fmtinstall('L', BLfmt);
292
	fmtinstall('B', BLfmt);
293
	fmtinstall('N', Nfmt);
294
	fmtinstall('D', Dfmt);
295
 
296
	fd = xfd;
297
	h = xh;
298
	file9660 = xfile9660;
299
	off9660 = xoff9660;
300
 
301
	if((b = Bopen(file9660, OREAD)) == nil)
302
		vtFatal("Bopen %s: %r", file9660);
303
 
304
	getsect(root, 16);
305
	ascii();
306
 
307
	v = (Voldesc*)root;
308
	if(memcmp(v->magic, "\x01CD001\x01\x00", 8) != 0)
309
		vtFatal("%s not a cd image", file9660);
310
 
311
	startoff = iso9660start((Cdir*)v->rootdir)*Blocksize;
312
	endoff = little(v->volsize, 4);	/* already in bytes */
313
 
314
	fsoff = off9660 + h->data*h->blockSize;
315
	if(fsoff > startoff)
316
		vtFatal("fossil data starts after cd data");
317
	if(off9660 + (vlong)h->end*h->blockSize < endoff)
318
		vtFatal("fossil data ends before cd data");
319
	if(fsoff%h->blockSize)
320
		vtFatal("cd offset not a multiple of fossil block size");
321
 
322
	/* Read "same" block via CD image and via Fossil image */
323
	getsect(sect, startoff/Blocksize);
324
	if(seek(fd, startoff-off9660, 0) < 0)
325
		vtFatal("cannot seek to first data sector on cd via fossil");
326
fprint(2, "look for %lud at %lud\n", startoff, startoff-off9660);
327
	if(readn(fd, sect2, Blocksize) != Blocksize)
328
		vtFatal("cannot read first data sector on cd via fossil");
329
	if(memcmp(sect, sect2, Blocksize) != 0)
330
		vtFatal("iso9660 offset is a lie %08ux %08ux", *(long*)sect, *(long*)sect2);
331
}
332
 
333
void
334
iso9660labels(Disk *disk, uchar *buf, void (*write)(int, u32int))
335
{
336
	ulong sb, eb, bn, lb, llb;
337
	Label l;
338
	int lpb;
339
	uchar sect[Blocksize];
340
 
341
	if(!diskReadRaw(disk, PartData, (startoff-fsoff)/h->blockSize, buf))
342
		vtFatal("disk read failed: %r");
343
	getsect(sect, startoff/Blocksize);
344
	if(memcmp(buf, sect, Blocksize) != 0)
345
		vtFatal("fsoff is wrong");
346
 
347
	sb = (startoff-fsoff)/h->blockSize;
348
	eb = (endoff-fsoff+h->blockSize-1)/h->blockSize;
349
 
350
	lpb = h->blockSize/LabelSize;
351
 
352
	/* for each reserved block, mark label */
353
	llb = ~0;
354
	l.type = BtData;
355
	l.state = BsAlloc;
356
	l.tag = Tag;
357
	l.epoch = 1;
358
	l.epochClose = ~(u32int)0;
359
	for(bn=sb; bn<eb; bn++){
360
		lb = bn/lpb;
361
		if(lb != llb){
362
			if(llb != ~0)
363
				(*write)(PartLabel, llb);
364
			memset(buf, 0, h->blockSize);
365
		}
366
		llb = lb;
367
		labelPack(&l, buf, bn%lpb);
368
	}
369
	if(llb != ~0)
370
		(*write)(PartLabel, llb);
371
}
372
 
373
void
374
iso9660copy(Fs *fs)
375
{
376
	File *root;
377
 
378
	root = fileOpen(fs, "/active");
379
	iso9660copydir(fs, root, (Cdir*)v->rootdir);
380
	fileDecRef(root);
381
	vtRUnlock(fs->elk);
382
	if(!fsSnapshot(fs, nil, nil, 0))
383
		vtFatal("snapshot failed: %R");
384
	vtRLock(fs->elk);
385
}
386
 
387
/*
388
 * The first block used is the first data block of the leftmost file in the tree.
389
 * (Just an artifact of how mk9660 works.)
390
 */
391
static ulong
392
iso9660start(Cdir *c)
393
{
394
	uchar sect[Blocksize];
395
 
396
	while(c->flags&2){
397
		getsect(sect, little(c->dloc, 4));
398
		c = (Cdir*)sect;
399
		c = (Cdir*)((uchar*)c+c->len);	/* skip dot */
400
		c = (Cdir*)((uchar*)c+c->len);	/* skip dotdot */
401
		/* oops: might happen if leftmost directory is empty or leftmost file is zero length! */
402
		if(little(c->dloc, 4) == 0)
403
			vtFatal("error parsing cd image or unfortunate cd image");	
404
	}
405
	return little(c->dloc, 4);
406
}
407
 
408
static void
409
iso9660copydir(Fs *fs, File *dir, Cdir *cd)
410
{
411
	ulong off, end, len;
412
	uchar sect[Blocksize], *esect, *p;
413
	Cdir *c;
414
 
415
	len = little(cd->dlen, 4);
416
	off = little(cd->dloc, 4)*Blocksize;
417
	end = off+len;
418
	esect = sect+Blocksize;
419
 
420
	for(; off<end; off+=Blocksize){
421
		getsect(sect, off/Blocksize);
422
		p = sect;
423
		while(p < esect){
424
			c = (Cdir*)p;
425
			if(c->len <= 0)
426
				break;
427
			if(c->namelen!=1 || c->name[0]>1)
428
				iso9660copyfile(fs, dir, c);
429
			p += c->len;
430
		}
431
	}
432
}
433
 
434
static char*
435
getname(uchar **pp)
436
{
437
	uchar *p;
438
	int l;
439
 
440
	p = *pp;
441
	l = *p;
442
	*pp = p+1+l;
443
	if(l == 0)
444
		return "";
445
	memmove(p, p+1, l);
446
	p[l] = 0;
447
	return (char*)p;
448
}
449
 
450
static char*
451
getcname(Cdir *c)
452
{
453
	uchar *up;
454
	char *p, *q;
455
 
456
	up = &c->namelen;
457
	p = getname(&up);
458
	for(q=p; *q; q++)
459
		*q = tolower(*q);
460
	return p;
461
}
462
 
463
static char
464
dmsize[12] =
465
{
466
	31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
467
};
468
 
469
static ulong
470
getcdate(uchar *p)	/* yMdhmsz */
471
{
472
	Tm tm;
473
	int y, M, d, h, m, s, tz;
474
 
475
	y=p[0]; M=p[1]; d=p[2];
476
	h=p[3]; m=p[4]; s=p[5]; tz=p[6];
477
	USED(tz);
478
	if (y < 70)
479
		return 0;
480
	if (M < 1 || M > 12)
481
		return 0;
482
	if (d < 1 || d > dmsize[M-1])
483
		return 0;
484
	if (h > 23)
485
		return 0;
486
	if (m > 59)
487
		return 0;
488
	if (s > 59)
489
		return 0;
490
 
491
	memset(&tm, 0, sizeof tm);
492
	tm.sec = s;
493
	tm.min = m;
494
	tm.hour = h;
495
	tm.mday = d;
496
	tm.mon = M-1;
497
	tm.year = 1900+y;
498
	tm.zone[0] = 0;
499
	return tm2sec(&tm);
500
}
501
 
502
static int ind;
503
 
504
static void
505
iso9660copyfile(Fs *fs, File *dir, Cdir *c)
506
{
507
	Dir d;
508
	DirEntry de;
509
	int sysl;
510
	uchar score[VtScoreSize];
511
	ulong off, foff, len, mode;
512
	uchar *p;
513
	File *f;
514
 
515
	ind++;
516
	memset(&d, 0, sizeof d);
517
	p = c->name + c->namelen;
518
	if(((uintptr)p) & 1)
519
		p++;
520
	sysl = (uchar*)c + c->len - p;
521
	if(sysl <= 0)
522
		vtFatal("missing plan9 directory entry on %d/%d/%.*s", c->namelen, c->name[0], c->namelen, c->name);
523
	d.name = getname(&p);
524
	d.uid = getname(&p);
525
	d.gid = getname(&p);
526
	if((uintptr)p & 1)
527
		p++;
528
	d.mode = little(p, 4);
529
	if(d.name[0] == 0)
530
		d.name = getcname(c);
531
	d.mtime = getcdate(c->date);
532
	d.atime = d.mtime;
533
 
534
if(d.mode&DMDIR)	print("%*scopy %s %s %s %luo\n", ind*2, "", d.name, d.uid, d.gid, d.mode);
535
 
536
	mode = d.mode&0777;
537
	if(d.mode&DMDIR)
538
		mode |= ModeDir;
539
	if((f = fileCreate(dir, d.name, mode, d.uid)) == nil)
540
		vtFatal("could not create file '%s': %r", d.name);
541
	if(d.mode&DMDIR)
542
		iso9660copydir(fs, f, c);
543
	else{
544
		len = little(c->dlen, 4);
545
		off = little(c->dloc, 4)*Blocksize;
546
		for(foff=0; foff<len; foff+=h->blockSize){
547
			localToGlobal((off+foff-fsoff)/h->blockSize, score);
548
			if(!fileMapBlock(f, foff/h->blockSize, score, Tag))
549
				vtFatal("fileMapBlock: %R");
550
		}
551
		if(!fileSetSize(f, len))
552
			vtFatal("fileSetSize: %R");
553
	}
554
	if(!fileGetDir(f, &de))
555
		vtFatal("fileGetDir: %R");
556
	de.uid = d.uid;
557
	de.gid = d.gid;
558
	de.mtime = d.mtime;
559
	de.atime = d.atime;
560
	de.mode = d.mode&0777;
561
	if(!fileSetDir(f, &de, "sys"))
562
		vtFatal("fileSetDir: %R");
563
	fileDecRef(f);
564
	ind--;
565
}