xref: /plan9/sys/src/cmd/disk/9660/cdrdwr.c (revision 3e33a36fadd1f83a7b3e74f4a2858d02601a619e)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <bio.h>
480ee5cbfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier 
680ee5cbfSDavid du Colombier #include "iso9660.h"
780ee5cbfSDavid du Colombier 
880ee5cbfSDavid du Colombier static int readisodesc(Cdimg*, Voldesc*);
980ee5cbfSDavid du Colombier static int readjolietdesc(Cdimg*, Voldesc*);
1080ee5cbfSDavid du Colombier 
1180ee5cbfSDavid du Colombier /*
1280ee5cbfSDavid du Colombier  * It's not strictly conforming; instead it's enough to
1380ee5cbfSDavid du Colombier  * get us up and running; presumably the real CD writing
1480ee5cbfSDavid du Colombier  * will take care of being conforming.
1580ee5cbfSDavid du Colombier  *
1680ee5cbfSDavid du Colombier  * Things not conforming include:
1780ee5cbfSDavid du Colombier  *	- no path table
1880ee5cbfSDavid du Colombier  *	- root directories are of length zero
1980ee5cbfSDavid du Colombier  */
2080ee5cbfSDavid du Colombier Cdimg*
2180ee5cbfSDavid du Colombier createcd(char *file, Cdinfo info)
2280ee5cbfSDavid du Colombier {
2380ee5cbfSDavid du Colombier 	int fd, xfd;
2480ee5cbfSDavid du Colombier 	Cdimg *cd;
2580ee5cbfSDavid du Colombier 
2680ee5cbfSDavid du Colombier 	if(access(file, AEXIST) == 0){
2780ee5cbfSDavid du Colombier 		werrstr("file already exists");
2880ee5cbfSDavid du Colombier 		return nil;
2980ee5cbfSDavid du Colombier 	}
3080ee5cbfSDavid du Colombier 
3180ee5cbfSDavid du Colombier 	if((fd = create(file, ORDWR, 0666)) < 0)
3280ee5cbfSDavid du Colombier 		return nil;
3380ee5cbfSDavid du Colombier 
3480ee5cbfSDavid du Colombier 	cd = emalloc(sizeof *cd);
3580ee5cbfSDavid du Colombier 	cd->file = atom(file);
3680ee5cbfSDavid du Colombier 
3780ee5cbfSDavid du Colombier 	Binit(&cd->brd, fd, OREAD);
3880ee5cbfSDavid du Colombier 
3980ee5cbfSDavid du Colombier 	if((xfd = open(file, ORDWR)) < 0)
4080ee5cbfSDavid du Colombier 		sysfatal("can't open file again: %r");
4180ee5cbfSDavid du Colombier 	Binit(&cd->bwr, xfd, OWRITE);
4280ee5cbfSDavid du Colombier 
4380ee5cbfSDavid du Colombier 	Crepeat(cd, 0, 16*Blocksize);
4480ee5cbfSDavid du Colombier 	Cputisopvd(cd, info);
459a747e4fSDavid du Colombier 	if(info.flags & CDbootable){
469a747e4fSDavid du Colombier 		cd->bootimage = info.bootimage;
4743751f27SDavid du Colombier 		cd->flags |= info.flags & (CDbootable|CDbootnoemu);
489a747e4fSDavid du Colombier 		Cputbootvol(cd);
499a747e4fSDavid du Colombier 	}
5080ee5cbfSDavid du Colombier 
5180ee5cbfSDavid du Colombier 	if(readisodesc(cd, &cd->iso) < 0)
5280ee5cbfSDavid du Colombier 		assert(0);
5380ee5cbfSDavid du Colombier 	if(info.flags & CDplan9)
5480ee5cbfSDavid du Colombier 		cd->flags |= CDplan9;
5580ee5cbfSDavid du Colombier 	else if(info.flags & CDrockridge)
5680ee5cbfSDavid du Colombier 		cd->flags |= CDrockridge;
5780ee5cbfSDavid du Colombier 	if(info.flags & CDjoliet) {
5880ee5cbfSDavid du Colombier 		Cputjolietsvd(cd, info);
5980ee5cbfSDavid du Colombier 		if(readjolietdesc(cd, &cd->joliet) < 0)
6080ee5cbfSDavid du Colombier 			assert(0);
6180ee5cbfSDavid du Colombier 		cd->flags |= CDjoliet;
6280ee5cbfSDavid du Colombier 	}
6380ee5cbfSDavid du Colombier 	Cputendvd(cd);
6480ee5cbfSDavid du Colombier 
6580ee5cbfSDavid du Colombier 	if(info.flags & CDdump){
6680ee5cbfSDavid du Colombier 		cd->nulldump = Cputdumpblock(cd);
6780ee5cbfSDavid du Colombier 		cd->flags |= CDdump;
6880ee5cbfSDavid du Colombier 	}
699a747e4fSDavid du Colombier 	if(cd->flags & CDbootable){
709a747e4fSDavid du Colombier 		Cputbootcat(cd);
719a747e4fSDavid du Colombier 		Cupdatebootvol(cd);
729a747e4fSDavid du Colombier 	}
7380ee5cbfSDavid du Colombier 
7480ee5cbfSDavid du Colombier 	if(info.flags & CDconform)
7580ee5cbfSDavid du Colombier 		cd->flags |= CDconform;
7680ee5cbfSDavid du Colombier 
7780ee5cbfSDavid du Colombier 	cd->flags |= CDnew;
7880ee5cbfSDavid du Colombier 	cd->nextblock = Cwoffset(cd) / Blocksize;
7980ee5cbfSDavid du Colombier 	assert(cd->nextblock != 0);
8080ee5cbfSDavid du Colombier 
8180ee5cbfSDavid du Colombier 	return cd;
8280ee5cbfSDavid du Colombier }
8380ee5cbfSDavid du Colombier 
8480ee5cbfSDavid du Colombier Cdimg*
8580ee5cbfSDavid du Colombier opencd(char *file, Cdinfo info)
8680ee5cbfSDavid du Colombier {
8780ee5cbfSDavid du Colombier 	int fd, xfd;
8880ee5cbfSDavid du Colombier 	Cdimg *cd;
899a747e4fSDavid du Colombier 	Dir *d;
9080ee5cbfSDavid du Colombier 
9180ee5cbfSDavid du Colombier 	if((fd = open(file, ORDWR)) < 0) {
9280ee5cbfSDavid du Colombier 		if(access(file, AEXIST) == 0)
9380ee5cbfSDavid du Colombier 			return nil;
9480ee5cbfSDavid du Colombier 		return createcd(file, info);
9580ee5cbfSDavid du Colombier 	}
9680ee5cbfSDavid du Colombier 
979a747e4fSDavid du Colombier 	if((d = dirfstat(fd)) == nil) {
9880ee5cbfSDavid du Colombier 		close(fd);
9980ee5cbfSDavid du Colombier 		return nil;
10080ee5cbfSDavid du Colombier 	}
1019a747e4fSDavid du Colombier 	if(d->length == 0 || d->length % Blocksize) {
1029a747e4fSDavid du Colombier 		werrstr("bad length %lld", d->length);
10380ee5cbfSDavid du Colombier 		close(fd);
1049a747e4fSDavid du Colombier 		free(d);
10580ee5cbfSDavid du Colombier 		return nil;
10680ee5cbfSDavid du Colombier 	}
10780ee5cbfSDavid du Colombier 
10880ee5cbfSDavid du Colombier 	cd = emalloc(sizeof *cd);
10980ee5cbfSDavid du Colombier 	cd->file = atom(file);
1109a747e4fSDavid du Colombier 	cd->nextblock = d->length / Blocksize;
11180ee5cbfSDavid du Colombier 	assert(cd->nextblock != 0);
1129a747e4fSDavid du Colombier 	free(d);
11380ee5cbfSDavid du Colombier 
11480ee5cbfSDavid du Colombier 	Binit(&cd->brd, fd, OREAD);
11580ee5cbfSDavid du Colombier 
11680ee5cbfSDavid du Colombier 	if((xfd = open(file, ORDWR)) < 0)
11780ee5cbfSDavid du Colombier 		sysfatal("can't open file again: %r");
11880ee5cbfSDavid du Colombier 	Binit(&cd->bwr, xfd, OWRITE);
11980ee5cbfSDavid du Colombier 
12080ee5cbfSDavid du Colombier 	if(readisodesc(cd, &cd->iso) < 0) {
12180ee5cbfSDavid du Colombier 		free(cd);
12280ee5cbfSDavid du Colombier 		close(fd);
12380ee5cbfSDavid du Colombier 		close(xfd);
12480ee5cbfSDavid du Colombier 		return nil;
12580ee5cbfSDavid du Colombier 	}
12680ee5cbfSDavid du Colombier 
12780ee5cbfSDavid du Colombier 	/* lowercase because of isostring */
12880ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "iso9660") == nil
12980ee5cbfSDavid du Colombier 	&& strstr(cd->iso.systemid, "utf8") == nil) {
13080ee5cbfSDavid du Colombier 		werrstr("unknown systemid %s", cd->iso.systemid);
13180ee5cbfSDavid du Colombier 		free(cd);
13280ee5cbfSDavid du Colombier 		close(fd);
13380ee5cbfSDavid du Colombier 		close(xfd);
13480ee5cbfSDavid du Colombier 		return nil;
13580ee5cbfSDavid du Colombier 	}
13680ee5cbfSDavid du Colombier 
13780ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "plan 9"))
13880ee5cbfSDavid du Colombier 		cd->flags |= CDplan9;
13980ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "iso9660"))
14080ee5cbfSDavid du Colombier 		cd->flags |= CDconform;
14180ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "rrip"))
14280ee5cbfSDavid du Colombier 		cd->flags |= CDrockridge;
1439a747e4fSDavid du Colombier 	if(strstr(cd->iso.systemid, "boot"))
1449a747e4fSDavid du Colombier 		cd->flags |= CDbootable;
14580ee5cbfSDavid du Colombier 	if(readjolietdesc(cd, &cd->joliet) == 0)
14680ee5cbfSDavid du Colombier 		cd->flags |= CDjoliet;
14780ee5cbfSDavid du Colombier 	if(hasdump(cd))
14880ee5cbfSDavid du Colombier 		cd->flags |= CDdump;
14980ee5cbfSDavid du Colombier 
15080ee5cbfSDavid du Colombier 	return cd;
15180ee5cbfSDavid du Colombier }
15280ee5cbfSDavid du Colombier 
15380ee5cbfSDavid du Colombier ulong
15480ee5cbfSDavid du Colombier big(void *a, int n)
15580ee5cbfSDavid du Colombier {
15680ee5cbfSDavid du Colombier 	uchar *p;
15780ee5cbfSDavid du Colombier 	ulong v;
15880ee5cbfSDavid du Colombier 	int i;
15980ee5cbfSDavid du Colombier 
16080ee5cbfSDavid du Colombier 	p = a;
16180ee5cbfSDavid du Colombier 	v = 0;
16280ee5cbfSDavid du Colombier 	for(i=0; i<n; i++)
16380ee5cbfSDavid du Colombier 		v = (v<<8) | *p++;
16480ee5cbfSDavid du Colombier 	return v;
16580ee5cbfSDavid du Colombier }
16680ee5cbfSDavid du Colombier 
16780ee5cbfSDavid du Colombier ulong
16880ee5cbfSDavid du Colombier little(void *a, int n)
16980ee5cbfSDavid du Colombier {
17080ee5cbfSDavid du Colombier 	uchar *p;
17180ee5cbfSDavid du Colombier 	ulong v;
17280ee5cbfSDavid du Colombier 	int i;
17380ee5cbfSDavid du Colombier 
17480ee5cbfSDavid du Colombier 	p = a;
17580ee5cbfSDavid du Colombier 	v = 0;
17680ee5cbfSDavid du Colombier 	for(i=0; i<n; i++)
17780ee5cbfSDavid du Colombier 		v |= (*p++<<(i*8));
17880ee5cbfSDavid du Colombier 	return v;
17980ee5cbfSDavid du Colombier }
18080ee5cbfSDavid du Colombier 
18180ee5cbfSDavid du Colombier void
18280ee5cbfSDavid du Colombier Creadblock(Cdimg *cd, void *buf, ulong block, ulong len)
18380ee5cbfSDavid du Colombier {
18480ee5cbfSDavid du Colombier 	assert(block != 0);	/* nothing useful there */
18580ee5cbfSDavid du Colombier 
18680ee5cbfSDavid du Colombier 	Bflush(&cd->bwr);
18773ee67a1SDavid du Colombier 	if(Bseek(&cd->brd, (vlong)block * Blocksize, 0) !=
18873ee67a1SDavid du Colombier 	    (vlong)block * Blocksize)
18980ee5cbfSDavid du Colombier 		sysfatal("error seeking to block %lud", block);
19080ee5cbfSDavid du Colombier 	if(Bread(&cd->brd, buf, len) != len)
19173ee67a1SDavid du Colombier 		sysfatal("error reading %lud bytes at block %lud: %r %lld",
19273ee67a1SDavid du Colombier 			len, block, Bseek(&cd->brd, 0, 2));
19380ee5cbfSDavid du Colombier }
19480ee5cbfSDavid du Colombier 
19580ee5cbfSDavid du Colombier int
19680ee5cbfSDavid du Colombier parsedir(Cdimg *cd, Direc *d, uchar *buf, int len, char *(*cvtname)(uchar*, int))
19780ee5cbfSDavid du Colombier {
1989a747e4fSDavid du Colombier 	enum { NAMELEN = 28 };
19980ee5cbfSDavid du Colombier 	char name[NAMELEN];
20080ee5cbfSDavid du Colombier 	uchar *p;
20180ee5cbfSDavid du Colombier 	Cdir *c;
20280ee5cbfSDavid du Colombier 
20380ee5cbfSDavid du Colombier 	memset(d, 0, sizeof *d);
20480ee5cbfSDavid du Colombier 
20580ee5cbfSDavid du Colombier 	c = (Cdir*)buf;
20680ee5cbfSDavid du Colombier 
20780ee5cbfSDavid du Colombier 	if(c->len > len) {
20880ee5cbfSDavid du Colombier 		werrstr("buffer too small");
20980ee5cbfSDavid du Colombier 		return -1;
21080ee5cbfSDavid du Colombier 	}
21180ee5cbfSDavid du Colombier 
21280ee5cbfSDavid du Colombier 	if(c->namelen == 1 && c->name[0] == '\0')
21380ee5cbfSDavid du Colombier 		d->name = atom(".");
21480ee5cbfSDavid du Colombier 	else if(c->namelen == 1 && c->name[0] == '\001')
21580ee5cbfSDavid du Colombier 		d->name = atom("..");
21680ee5cbfSDavid du Colombier 	else if(cvtname)
21780ee5cbfSDavid du Colombier 		d->name = cvtname(c->name, c->namelen);
21880ee5cbfSDavid du Colombier 
21980ee5cbfSDavid du Colombier 	d->block = little(c->dloc, 4);
22080ee5cbfSDavid du Colombier 	d->length = little(c->dlen, 4);
22180ee5cbfSDavid du Colombier 
22280ee5cbfSDavid du Colombier 	if(c->flags & 2)
2239a747e4fSDavid du Colombier 		d->mode |= DMDIR;
22480ee5cbfSDavid du Colombier 
22580ee5cbfSDavid du Colombier /*BUG: do we really need to parse the plan 9 fields? */
22680ee5cbfSDavid du Colombier 	/* plan 9 use fields */
22780ee5cbfSDavid du Colombier 	if((cd->flags & CDplan9) && cvtname == isostring
22880ee5cbfSDavid du Colombier 	&& (c->namelen != 1 || c->name[0] > 1)) {
22980ee5cbfSDavid du Colombier 		p = buf+33+c->namelen;
23080ee5cbfSDavid du Colombier 		if((p-buf)&1)
23180ee5cbfSDavid du Colombier 			p++;
23280ee5cbfSDavid du Colombier 		assert(p < buf+c->len);
23380ee5cbfSDavid du Colombier 		assert(*p < NAMELEN);
23480ee5cbfSDavid du Colombier 		if(*p != 0) {
23580ee5cbfSDavid du Colombier 			memmove(name, p+1, *p);
23680ee5cbfSDavid du Colombier 			name[*p] = '\0';
23780ee5cbfSDavid du Colombier 			d->confname = d->name;
23880ee5cbfSDavid du Colombier 			d->name = atom(name);
23980ee5cbfSDavid du Colombier 		}
24080ee5cbfSDavid du Colombier 		p += *p+1;
24180ee5cbfSDavid du Colombier 		assert(*p < NAMELEN);
24280ee5cbfSDavid du Colombier 		memmove(name, p+1, *p);
24380ee5cbfSDavid du Colombier 		name[*p] = '\0';
24480ee5cbfSDavid du Colombier 		d->uid = atom(name);
24580ee5cbfSDavid du Colombier 		p += *p+1;
24680ee5cbfSDavid du Colombier 		assert(*p < NAMELEN);
24780ee5cbfSDavid du Colombier 		memmove(name, p+1, *p);
24880ee5cbfSDavid du Colombier 		name[*p] = '\0';
24980ee5cbfSDavid du Colombier 		d->gid = atom(name);
25080ee5cbfSDavid du Colombier 		p += *p+1;
25180ee5cbfSDavid du Colombier 		if((p-buf)&1)
25280ee5cbfSDavid du Colombier 			p++;
25380ee5cbfSDavid du Colombier 		d->mode = little(p, 4);
25480ee5cbfSDavid du Colombier 	}
25580ee5cbfSDavid du Colombier 
25680ee5cbfSDavid du Colombier 	// BUG: rock ridge extensions
25780ee5cbfSDavid du Colombier 	return 0;
25880ee5cbfSDavid du Colombier }
25980ee5cbfSDavid du Colombier 
26080ee5cbfSDavid du Colombier void
26180ee5cbfSDavid du Colombier setroot(Cdimg *cd, ulong block, ulong dloc, ulong dlen)
26280ee5cbfSDavid du Colombier {
26380ee5cbfSDavid du Colombier 	assert(block != 0);
26480ee5cbfSDavid du Colombier 
26573ee67a1SDavid du Colombier 	Cwseek(cd, (vlong)block * Blocksize + offsetof(Cvoldesc, rootdir[0]) +
26673ee67a1SDavid du Colombier 		offsetof(Cdir, dloc[0]));
26780ee5cbfSDavid du Colombier 	Cputn(cd, dloc, 4);
26880ee5cbfSDavid du Colombier 	Cputn(cd, dlen, 4);
26980ee5cbfSDavid du Colombier }
27080ee5cbfSDavid du Colombier 
27180ee5cbfSDavid du Colombier void
272*3e33a36fSDavid du Colombier setvolsize(Cdimg *cd, uvlong block, ulong size)
27380ee5cbfSDavid du Colombier {
27480ee5cbfSDavid du Colombier 	assert(block != 0);
27580ee5cbfSDavid du Colombier 
276*3e33a36fSDavid du Colombier 	Cwseek(cd, block * Blocksize + offsetof(Cvoldesc, volsize[0]));
27780ee5cbfSDavid du Colombier 	Cputn(cd, size, 4);
27880ee5cbfSDavid du Colombier }
27980ee5cbfSDavid du Colombier 
28080ee5cbfSDavid du Colombier void
28180ee5cbfSDavid du Colombier setpathtable(Cdimg *cd, ulong block, ulong sz, ulong lloc, ulong bloc)
28280ee5cbfSDavid du Colombier {
28380ee5cbfSDavid du Colombier 	assert(block != 0);
28480ee5cbfSDavid du Colombier 
28573ee67a1SDavid du Colombier 	Cwseek(cd, (vlong)block * Blocksize + offsetof(Cvoldesc, pathsize[0]));
28680ee5cbfSDavid du Colombier 	Cputn(cd, sz, 4);
28780ee5cbfSDavid du Colombier 	Cputnl(cd, lloc, 4);
28880ee5cbfSDavid du Colombier 	Cputnl(cd, 0, 4);
28980ee5cbfSDavid du Colombier 	Cputnm(cd, bloc, 4);
29080ee5cbfSDavid du Colombier 	Cputnm(cd, 0, 4);
29173ee67a1SDavid du Colombier 	assert(Cwoffset(cd) == (vlong)block * Blocksize +
29273ee67a1SDavid du Colombier 		offsetof(Cvoldesc, rootdir[0]));
29380ee5cbfSDavid du Colombier }
29480ee5cbfSDavid du Colombier 
29580ee5cbfSDavid du Colombier 
29680ee5cbfSDavid du Colombier static void
29780ee5cbfSDavid du Colombier parsedesc(Voldesc *v, Cvoldesc *cv, char *(*string)(uchar*, int))
29880ee5cbfSDavid du Colombier {
29980ee5cbfSDavid du Colombier 	v->systemid = string(cv->systemid, sizeof cv->systemid);
30080ee5cbfSDavid du Colombier 
30180ee5cbfSDavid du Colombier 	v->pathsize = little(cv->pathsize, 4);
30280ee5cbfSDavid du Colombier 	v->lpathloc = little(cv->lpathloc, 4);
30380ee5cbfSDavid du Colombier 	v->mpathloc = little(cv->mpathloc, 4);
30480ee5cbfSDavid du Colombier 
30580ee5cbfSDavid du Colombier 	v->volumeset = string(cv->volumeset, sizeof cv->volumeset);
30680ee5cbfSDavid du Colombier 	v->publisher = string(cv->publisher, sizeof cv->publisher);
30780ee5cbfSDavid du Colombier 	v->preparer = string(cv->preparer, sizeof cv->preparer);
30880ee5cbfSDavid du Colombier 	v->application = string(cv->application, sizeof cv->application);
30980ee5cbfSDavid du Colombier 
31080ee5cbfSDavid du Colombier 	v->abstract = string(cv->abstract, sizeof cv->abstract);
31180ee5cbfSDavid du Colombier 	v->biblio = string(cv->biblio, sizeof cv->biblio);
31280ee5cbfSDavid du Colombier 	v->notice = string(cv->notice, sizeof cv->notice);
31380ee5cbfSDavid du Colombier }
31480ee5cbfSDavid du Colombier 
31580ee5cbfSDavid du Colombier static int
31680ee5cbfSDavid du Colombier readisodesc(Cdimg *cd, Voldesc *v)
31780ee5cbfSDavid du Colombier {
31880ee5cbfSDavid du Colombier 	static uchar magic[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
31980ee5cbfSDavid du Colombier 	Cvoldesc cv;
32080ee5cbfSDavid du Colombier 
32180ee5cbfSDavid du Colombier 	memset(v, 0, sizeof *v);
32280ee5cbfSDavid du Colombier 
32380ee5cbfSDavid du Colombier 	Creadblock(cd, &cv, 16, sizeof cv);
32480ee5cbfSDavid du Colombier 	if(memcmp(cv.magic, magic, sizeof magic) != 0) {
32580ee5cbfSDavid du Colombier 		werrstr("bad pvd magic");
32680ee5cbfSDavid du Colombier 		return -1;
32780ee5cbfSDavid du Colombier 	}
32880ee5cbfSDavid du Colombier 
32980ee5cbfSDavid du Colombier 	if(little(cv.blocksize, 2) != Blocksize) {
33080ee5cbfSDavid du Colombier 		werrstr("block size not %d", Blocksize);
33180ee5cbfSDavid du Colombier 		return -1;
33280ee5cbfSDavid du Colombier 	}
33380ee5cbfSDavid du Colombier 
33480ee5cbfSDavid du Colombier 	cd->iso9660pvd = 16;
33580ee5cbfSDavid du Colombier 	parsedesc(v, &cv, isostring);
33680ee5cbfSDavid du Colombier 
33780ee5cbfSDavid du Colombier 	return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, isostring);
33880ee5cbfSDavid du Colombier }
33980ee5cbfSDavid du Colombier 
34080ee5cbfSDavid du Colombier static int
34180ee5cbfSDavid du Colombier readjolietdesc(Cdimg *cd, Voldesc *v)
34280ee5cbfSDavid du Colombier {
34380ee5cbfSDavid du Colombier 	int i;
34480ee5cbfSDavid du Colombier 	static uchar magic[] = { 0x02, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
34580ee5cbfSDavid du Colombier 	Cvoldesc cv;
34680ee5cbfSDavid du Colombier 
34780ee5cbfSDavid du Colombier 	memset(v, 0, sizeof *v);
34880ee5cbfSDavid du Colombier 
34980ee5cbfSDavid du Colombier 	for(i=16; i<24; i++) {
35080ee5cbfSDavid du Colombier 		Creadblock(cd, &cv, i, sizeof cv);
35180ee5cbfSDavid du Colombier 		if(memcmp(cv.magic, magic, sizeof magic) != 0)
35280ee5cbfSDavid du Colombier 			continue;
35380ee5cbfSDavid du Colombier 		if(cv.charset[0] != 0x25 || cv.charset[1] != 0x2F
35480ee5cbfSDavid du Colombier 		|| (cv.charset[2] != 0x40 && cv.charset[2] != 0x43 && cv.charset[2] != 0x45))
35580ee5cbfSDavid du Colombier 			continue;
35680ee5cbfSDavid du Colombier 		break;
35780ee5cbfSDavid du Colombier 	}
35880ee5cbfSDavid du Colombier 
35980ee5cbfSDavid du Colombier 	if(i==24) {
36080ee5cbfSDavid du Colombier 		werrstr("could not find Joliet SVD");
36180ee5cbfSDavid du Colombier 		return -1;
36280ee5cbfSDavid du Colombier 	}
36380ee5cbfSDavid du Colombier 
36480ee5cbfSDavid du Colombier 	if(little(cv.blocksize, 2) != Blocksize) {
36580ee5cbfSDavid du Colombier 		werrstr("block size not %d", Blocksize);
36680ee5cbfSDavid du Colombier 		return -1;
36780ee5cbfSDavid du Colombier 	}
36880ee5cbfSDavid du Colombier 
36980ee5cbfSDavid du Colombier 	cd->jolietsvd = i;
37080ee5cbfSDavid du Colombier 	parsedesc(v, &cv, jolietstring);
37180ee5cbfSDavid du Colombier 
37280ee5cbfSDavid du Colombier 	return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, jolietstring);
37380ee5cbfSDavid du Colombier }
37480ee5cbfSDavid du Colombier 
37580ee5cbfSDavid du Colombier /*
37680ee5cbfSDavid du Colombier  * CD image buffering routines.
37780ee5cbfSDavid du Colombier  */
37880ee5cbfSDavid du Colombier void
37980ee5cbfSDavid du Colombier Cputc(Cdimg *cd, int c)
38080ee5cbfSDavid du Colombier {
38180ee5cbfSDavid du Colombier 	assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0);
38280ee5cbfSDavid du Colombier 
38380ee5cbfSDavid du Colombier if(Boffset(&cd->bwr) == 0x9962)
38480ee5cbfSDavid du Colombier if(c >= 256) abort();
38580ee5cbfSDavid du Colombier 	if(Bputc(&cd->bwr, c) < 0)
38680ee5cbfSDavid du Colombier 		sysfatal("Bputc: %r");
38780ee5cbfSDavid du Colombier 	Bflush(&cd->brd);
38880ee5cbfSDavid du Colombier }
38980ee5cbfSDavid du Colombier 
39080ee5cbfSDavid du Colombier void
391*3e33a36fSDavid du Colombier Cputnl(Cdimg *cd, uvlong val, int size)
39280ee5cbfSDavid du Colombier {
39380ee5cbfSDavid du Colombier 	switch(size) {
39480ee5cbfSDavid du Colombier 	default:
395*3e33a36fSDavid du Colombier 		sysfatal("bad size %d in Cputnl", size);
39680ee5cbfSDavid du Colombier 	case 2:
397*3e33a36fSDavid du Colombier 		if(val >= (1<<16))
398*3e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
399*3e33a36fSDavid du Colombier 				val, size);
40080ee5cbfSDavid du Colombier 		Cputc(cd, val);
40180ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
40280ee5cbfSDavid du Colombier 		break;
40380ee5cbfSDavid du Colombier 	case 4:
404*3e33a36fSDavid du Colombier 		if(val >= (1ULL<<32))
405*3e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
406*3e33a36fSDavid du Colombier 				val, size);
40780ee5cbfSDavid du Colombier 		Cputc(cd, val);
40880ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
40980ee5cbfSDavid du Colombier 		Cputc(cd, val>>16);
41080ee5cbfSDavid du Colombier 		Cputc(cd, val>>24);
41180ee5cbfSDavid du Colombier 		break;
412*3e33a36fSDavid du Colombier 	case 8:
413*3e33a36fSDavid du Colombier 		Cputc(cd, val);
414*3e33a36fSDavid du Colombier 		Cputc(cd, val>>8);
415*3e33a36fSDavid du Colombier 		Cputc(cd, val>>16);
416*3e33a36fSDavid du Colombier 		Cputc(cd, val>>24);
417*3e33a36fSDavid du Colombier 		Cputc(cd, val>>32);
418*3e33a36fSDavid du Colombier 		Cputc(cd, val>>40);
419*3e33a36fSDavid du Colombier 		Cputc(cd, val>>48);
420*3e33a36fSDavid du Colombier 		Cputc(cd, val>>56);
421*3e33a36fSDavid du Colombier 		break;
42280ee5cbfSDavid du Colombier 	}
42380ee5cbfSDavid du Colombier }
42480ee5cbfSDavid du Colombier 
42580ee5cbfSDavid du Colombier void
426*3e33a36fSDavid du Colombier Cputnm(Cdimg *cd, uvlong val, int size)
42780ee5cbfSDavid du Colombier {
42880ee5cbfSDavid du Colombier 	switch(size) {
42980ee5cbfSDavid du Colombier 	default:
430*3e33a36fSDavid du Colombier 		sysfatal("bad size %d in Cputnm", size);
43180ee5cbfSDavid du Colombier 	case 2:
432*3e33a36fSDavid du Colombier 		if(val >= (1<<16))
433*3e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
434*3e33a36fSDavid du Colombier 				val, size);
43580ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
43680ee5cbfSDavid du Colombier 		Cputc(cd, val);
43780ee5cbfSDavid du Colombier 		break;
43880ee5cbfSDavid du Colombier 	case 4:
439*3e33a36fSDavid du Colombier 		if(val >= (1ULL<<32))
440*3e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
441*3e33a36fSDavid du Colombier 				val, size);
442*3e33a36fSDavid du Colombier 		Cputc(cd, val>>24);
443*3e33a36fSDavid du Colombier 		Cputc(cd, val>>16);
444*3e33a36fSDavid du Colombier 		Cputc(cd, val>>8);
445*3e33a36fSDavid du Colombier 		Cputc(cd, val);
446*3e33a36fSDavid du Colombier 		break;
447*3e33a36fSDavid du Colombier 	case 8:
448*3e33a36fSDavid du Colombier 		Cputc(cd, val>>56);
449*3e33a36fSDavid du Colombier 		Cputc(cd, val>>48);
450*3e33a36fSDavid du Colombier 		Cputc(cd, val>>40);
451*3e33a36fSDavid du Colombier 		Cputc(cd, val>>32);
45280ee5cbfSDavid du Colombier 		Cputc(cd, val>>24);
45380ee5cbfSDavid du Colombier 		Cputc(cd, val>>16);
45480ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
45580ee5cbfSDavid du Colombier 		Cputc(cd, val);
45680ee5cbfSDavid du Colombier 		break;
45780ee5cbfSDavid du Colombier 	}
45880ee5cbfSDavid du Colombier }
45980ee5cbfSDavid du Colombier 
46080ee5cbfSDavid du Colombier void
461*3e33a36fSDavid du Colombier Cputn(Cdimg *cd, uvlong val, int size)
46280ee5cbfSDavid du Colombier {
46380ee5cbfSDavid du Colombier 	Cputnl(cd, val, size);
46480ee5cbfSDavid du Colombier 	Cputnm(cd, val, size);
46580ee5cbfSDavid du Colombier }
46680ee5cbfSDavid du Colombier 
46780ee5cbfSDavid du Colombier /*
46880ee5cbfSDavid du Colombier  * ASCII/UTF string writing
46980ee5cbfSDavid du Colombier  */
47080ee5cbfSDavid du Colombier void
47180ee5cbfSDavid du Colombier Crepeat(Cdimg *cd, int c, int n)
47280ee5cbfSDavid du Colombier {
47380ee5cbfSDavid du Colombier 	while(n-- > 0)
47480ee5cbfSDavid du Colombier 		Cputc(cd, c);
47580ee5cbfSDavid du Colombier }
47680ee5cbfSDavid du Colombier 
47780ee5cbfSDavid du Colombier void
47880ee5cbfSDavid du Colombier Cputs(Cdimg *cd, char *s, int size)
47980ee5cbfSDavid du Colombier {
48080ee5cbfSDavid du Colombier 	int n;
48180ee5cbfSDavid du Colombier 
48280ee5cbfSDavid du Colombier 	if(s == nil) {
48380ee5cbfSDavid du Colombier 		Crepeat(cd, ' ', size);
48480ee5cbfSDavid du Colombier 		return;
48580ee5cbfSDavid du Colombier 	}
48680ee5cbfSDavid du Colombier 
48780ee5cbfSDavid du Colombier 	for(n=0; n<size && *s; n++)
48880ee5cbfSDavid du Colombier 		Cputc(cd, *s++);
48980ee5cbfSDavid du Colombier 	if(n<size)
49080ee5cbfSDavid du Colombier 		Crepeat(cd, ' ', size-n);
49180ee5cbfSDavid du Colombier }
49280ee5cbfSDavid du Colombier 
49380ee5cbfSDavid du Colombier void
49480ee5cbfSDavid du Colombier Cwrite(Cdimg *cd, void *buf, int n)
49580ee5cbfSDavid du Colombier {
49680ee5cbfSDavid du Colombier 	assert(Boffset(&cd->bwr) >= 16*Blocksize);
49780ee5cbfSDavid du Colombier 
49880ee5cbfSDavid du Colombier 	if(Bwrite(&cd->bwr, buf, n) != n)
49980ee5cbfSDavid du Colombier 		sysfatal("Bwrite: %r");
50080ee5cbfSDavid du Colombier 	Bflush(&cd->brd);
50180ee5cbfSDavid du Colombier }
50280ee5cbfSDavid du Colombier 
50380ee5cbfSDavid du Colombier void
50480ee5cbfSDavid du Colombier Cputr(Cdimg *cd, Rune r)
50580ee5cbfSDavid du Colombier {
50680ee5cbfSDavid du Colombier 	Cputc(cd, r>>8);
50780ee5cbfSDavid du Colombier 	Cputc(cd, r);
50880ee5cbfSDavid du Colombier }
50980ee5cbfSDavid du Colombier 
51080ee5cbfSDavid du Colombier void
51180ee5cbfSDavid du Colombier Crepeatr(Cdimg *cd, Rune r, int n)
51280ee5cbfSDavid du Colombier {
51380ee5cbfSDavid du Colombier 	int i;
51480ee5cbfSDavid du Colombier 
51580ee5cbfSDavid du Colombier 	for(i=0; i<n; i++)
51680ee5cbfSDavid du Colombier 		Cputr(cd, r);
51780ee5cbfSDavid du Colombier }
51880ee5cbfSDavid du Colombier 
51980ee5cbfSDavid du Colombier void
52080ee5cbfSDavid du Colombier Cputrs(Cdimg *cd, Rune *s, int osize)
52180ee5cbfSDavid du Colombier {
52280ee5cbfSDavid du Colombier 	int n, size;
52380ee5cbfSDavid du Colombier 
52480ee5cbfSDavid du Colombier 	size = osize/2;
52580ee5cbfSDavid du Colombier 	if(s == nil)
52680ee5cbfSDavid du Colombier 		Crepeatr(cd, (Rune)' ', size);
52780ee5cbfSDavid du Colombier 	else {
52880ee5cbfSDavid du Colombier 		for(n=0; *s && n<size; n++)
52980ee5cbfSDavid du Colombier 			Cputr(cd, *s++);
53080ee5cbfSDavid du Colombier 		if(n<size)
53180ee5cbfSDavid du Colombier 			Crepeatr(cd, ' ', size-n);
53280ee5cbfSDavid du Colombier 	}
53380ee5cbfSDavid du Colombier 	if(osize&1)
53480ee5cbfSDavid du Colombier 		Cputc(cd, 0);	/* what else can we do? */
53580ee5cbfSDavid du Colombier }
53680ee5cbfSDavid du Colombier 
53780ee5cbfSDavid du Colombier void
53880ee5cbfSDavid du Colombier Cputrscvt(Cdimg *cd, char *s, int size)
53980ee5cbfSDavid du Colombier {
54080ee5cbfSDavid du Colombier 	Rune r[256];
54180ee5cbfSDavid du Colombier 
54280ee5cbfSDavid du Colombier 	strtorune(r, s);
54380ee5cbfSDavid du Colombier 	Cputrs(cd, strtorune(r, s), size);
54480ee5cbfSDavid du Colombier }
54580ee5cbfSDavid du Colombier 
54680ee5cbfSDavid du Colombier void
54780ee5cbfSDavid du Colombier Cpadblock(Cdimg *cd)
54880ee5cbfSDavid du Colombier {
54980ee5cbfSDavid du Colombier 	int n;
55080ee5cbfSDavid du Colombier 	ulong nb;
55180ee5cbfSDavid du Colombier 
55280ee5cbfSDavid du Colombier 	n = Blocksize - (Boffset(&cd->bwr) % Blocksize);
55380ee5cbfSDavid du Colombier 	if(n != Blocksize)
55480ee5cbfSDavid du Colombier 		Crepeat(cd, 0, n);
55580ee5cbfSDavid du Colombier 
55680ee5cbfSDavid du Colombier 	nb = Boffset(&cd->bwr)/Blocksize;
55780ee5cbfSDavid du Colombier 	assert(nb != 0);
55880ee5cbfSDavid du Colombier 	if(nb > cd->nextblock)
55980ee5cbfSDavid du Colombier 		cd->nextblock = nb;
56080ee5cbfSDavid du Colombier }
56180ee5cbfSDavid du Colombier 
56280ee5cbfSDavid du Colombier void
56380ee5cbfSDavid du Colombier Cputdate(Cdimg *cd, ulong ust)
56480ee5cbfSDavid du Colombier {
56580ee5cbfSDavid du Colombier 	Tm *tm;
56680ee5cbfSDavid du Colombier 
56780ee5cbfSDavid du Colombier 	if(ust == 0) {
56880ee5cbfSDavid du Colombier 		Crepeat(cd, 0, 7);
56980ee5cbfSDavid du Colombier 		return;
57080ee5cbfSDavid du Colombier 	}
57180ee5cbfSDavid du Colombier 	tm = gmtime(ust);
57280ee5cbfSDavid du Colombier 	Cputc(cd, tm->year);
57380ee5cbfSDavid du Colombier 	Cputc(cd, tm->mon+1);
57480ee5cbfSDavid du Colombier 	Cputc(cd, tm->mday);
57580ee5cbfSDavid du Colombier 	Cputc(cd, tm->hour);
57680ee5cbfSDavid du Colombier 	Cputc(cd, tm->min);
57780ee5cbfSDavid du Colombier 	Cputc(cd, tm->sec);
57880ee5cbfSDavid du Colombier 	Cputc(cd, 0);
57980ee5cbfSDavid du Colombier }
58080ee5cbfSDavid du Colombier 
58180ee5cbfSDavid du Colombier void
58280ee5cbfSDavid du Colombier Cputdate1(Cdimg *cd, ulong ust)
58380ee5cbfSDavid du Colombier {
58480ee5cbfSDavid du Colombier 	Tm *tm;
58580ee5cbfSDavid du Colombier 	char str[20];
58680ee5cbfSDavid du Colombier 
58780ee5cbfSDavid du Colombier 	if(ust == 0) {
58880ee5cbfSDavid du Colombier 		Crepeat(cd, '0', 16);
58980ee5cbfSDavid du Colombier 		Cputc(cd, 0);
59080ee5cbfSDavid du Colombier 		return;
59180ee5cbfSDavid du Colombier 	}
59280ee5cbfSDavid du Colombier 	tm = gmtime(ust);
59380ee5cbfSDavid du Colombier 	sprint(str, "%.4d%.2d%.2d%.2d%.2d%.4d",
59480ee5cbfSDavid du Colombier 		tm->year+1900,
59580ee5cbfSDavid du Colombier 		tm->mon+1,
59680ee5cbfSDavid du Colombier 		tm->mday,
59780ee5cbfSDavid du Colombier 		tm->hour,
59880ee5cbfSDavid du Colombier 		tm->min,
59980ee5cbfSDavid du Colombier 		tm->sec*100);
60080ee5cbfSDavid du Colombier 	Cputs(cd, str, 16);
60180ee5cbfSDavid du Colombier 	Cputc(cd, 0);
60280ee5cbfSDavid du Colombier }
60380ee5cbfSDavid du Colombier 
60480ee5cbfSDavid du Colombier void
60573ee67a1SDavid du Colombier Cwseek(Cdimg *cd, vlong offset)
60680ee5cbfSDavid du Colombier {
60780ee5cbfSDavid du Colombier 	Bseek(&cd->bwr, offset, 0);
60880ee5cbfSDavid du Colombier }
60980ee5cbfSDavid du Colombier 
61073ee67a1SDavid du Colombier uvlong
61180ee5cbfSDavid du Colombier Cwoffset(Cdimg *cd)
61280ee5cbfSDavid du Colombier {
61380ee5cbfSDavid du Colombier 	return Boffset(&cd->bwr);
61480ee5cbfSDavid du Colombier }
61580ee5cbfSDavid du Colombier 
61680ee5cbfSDavid du Colombier void
61780ee5cbfSDavid du Colombier Cwflush(Cdimg *cd)
61880ee5cbfSDavid du Colombier {
61980ee5cbfSDavid du Colombier 	Bflush(&cd->bwr);
62080ee5cbfSDavid du Colombier }
62180ee5cbfSDavid du Colombier 
62273ee67a1SDavid du Colombier uvlong
62380ee5cbfSDavid du Colombier Croffset(Cdimg *cd)
62480ee5cbfSDavid du Colombier {
62580ee5cbfSDavid du Colombier 	return Boffset(&cd->brd);
62680ee5cbfSDavid du Colombier }
62780ee5cbfSDavid du Colombier 
62880ee5cbfSDavid du Colombier void
62973ee67a1SDavid du Colombier Crseek(Cdimg *cd, vlong offset)
63080ee5cbfSDavid du Colombier {
63180ee5cbfSDavid du Colombier 	Bseek(&cd->brd, offset, 0);
63280ee5cbfSDavid du Colombier }
63380ee5cbfSDavid du Colombier 
63480ee5cbfSDavid du Colombier int
63580ee5cbfSDavid du Colombier Cgetc(Cdimg *cd)
63680ee5cbfSDavid du Colombier {
63780ee5cbfSDavid du Colombier 	int c;
63880ee5cbfSDavid du Colombier 
63980ee5cbfSDavid du Colombier 	Cwflush(cd);
64080ee5cbfSDavid du Colombier 	if((c = Bgetc(&cd->brd)) == Beof) {
64173ee67a1SDavid du Colombier 		fprint(2, "getc at %llud\n", Croffset(cd));
64280ee5cbfSDavid du Colombier 		assert(0);
64380ee5cbfSDavid du Colombier 		//sysfatal("Bgetc: %r");
64480ee5cbfSDavid du Colombier 	}
64580ee5cbfSDavid du Colombier 	return c;
64680ee5cbfSDavid du Colombier }
64780ee5cbfSDavid du Colombier 
64880ee5cbfSDavid du Colombier void
64980ee5cbfSDavid du Colombier Cread(Cdimg *cd, void *buf, int n)
65080ee5cbfSDavid du Colombier {
65180ee5cbfSDavid du Colombier 	Cwflush(cd);
65280ee5cbfSDavid du Colombier 	if(Bread(&cd->brd, buf, n) != n)
65380ee5cbfSDavid du Colombier 		sysfatal("Bread: %r");
65480ee5cbfSDavid du Colombier }
65580ee5cbfSDavid du Colombier 
65680ee5cbfSDavid du Colombier char*
65780ee5cbfSDavid du Colombier Crdline(Cdimg *cd, int c)
65880ee5cbfSDavid du Colombier {
65980ee5cbfSDavid du Colombier 	Cwflush(cd);
66080ee5cbfSDavid du Colombier 	return Brdline(&cd->brd, c);
66180ee5cbfSDavid du Colombier }
66280ee5cbfSDavid du Colombier 
66380ee5cbfSDavid du Colombier int
66480ee5cbfSDavid du Colombier Clinelen(Cdimg *cd)
66580ee5cbfSDavid du Colombier {
66680ee5cbfSDavid du Colombier 	return Blinelen(&cd->brd);
66780ee5cbfSDavid du Colombier }
66880ee5cbfSDavid du Colombier 
669