xref: /plan9/sys/src/cmd/disk/9660/cdrdwr.c (revision a587111c8770e522e3667ff2b63cba8a77811dd9)
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*
createcd(char * file,Cdinfo info)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;
47f7db6155SDavid du Colombier 		cd->loader = info.loader;
4843751f27SDavid du Colombier 		cd->flags |= info.flags & (CDbootable|CDbootnoemu);
499a747e4fSDavid du Colombier 		Cputbootvol(cd);
509a747e4fSDavid du Colombier 	}
5180ee5cbfSDavid du Colombier 
5280ee5cbfSDavid du Colombier 	if(readisodesc(cd, &cd->iso) < 0)
5380ee5cbfSDavid du Colombier 		assert(0);
5480ee5cbfSDavid du Colombier 	if(info.flags & CDplan9)
5580ee5cbfSDavid du Colombier 		cd->flags |= CDplan9;
5680ee5cbfSDavid du Colombier 	else if(info.flags & CDrockridge)
5780ee5cbfSDavid du Colombier 		cd->flags |= CDrockridge;
5880ee5cbfSDavid du Colombier 	if(info.flags & CDjoliet) {
5980ee5cbfSDavid du Colombier 		Cputjolietsvd(cd, info);
6080ee5cbfSDavid du Colombier 		if(readjolietdesc(cd, &cd->joliet) < 0)
6180ee5cbfSDavid du Colombier 			assert(0);
6280ee5cbfSDavid du Colombier 		cd->flags |= CDjoliet;
6380ee5cbfSDavid du Colombier 	}
6480ee5cbfSDavid du Colombier 	Cputendvd(cd);
6580ee5cbfSDavid du Colombier 
6680ee5cbfSDavid du Colombier 	if(info.flags & CDdump){
6780ee5cbfSDavid du Colombier 		cd->nulldump = Cputdumpblock(cd);
6880ee5cbfSDavid du Colombier 		cd->flags |= CDdump;
6980ee5cbfSDavid du Colombier 	}
709a747e4fSDavid du Colombier 	if(cd->flags & CDbootable){
719a747e4fSDavid du Colombier 		Cputbootcat(cd);
729a747e4fSDavid du Colombier 		Cupdatebootvol(cd);
739a747e4fSDavid du Colombier 	}
7480ee5cbfSDavid du Colombier 
7580ee5cbfSDavid du Colombier 	if(info.flags & CDconform)
7680ee5cbfSDavid du Colombier 		cd->flags |= CDconform;
7780ee5cbfSDavid du Colombier 
7880ee5cbfSDavid du Colombier 	cd->flags |= CDnew;
7980ee5cbfSDavid du Colombier 	cd->nextblock = Cwoffset(cd) / Blocksize;
8080ee5cbfSDavid du Colombier 	assert(cd->nextblock != 0);
8180ee5cbfSDavid du Colombier 
8280ee5cbfSDavid du Colombier 	return cd;
8380ee5cbfSDavid du Colombier }
8480ee5cbfSDavid du Colombier 
8580ee5cbfSDavid du Colombier Cdimg*
opencd(char * file,Cdinfo info)8680ee5cbfSDavid du Colombier opencd(char *file, Cdinfo info)
8780ee5cbfSDavid du Colombier {
8880ee5cbfSDavid du Colombier 	int fd, xfd;
8980ee5cbfSDavid du Colombier 	Cdimg *cd;
909a747e4fSDavid du Colombier 	Dir *d;
9180ee5cbfSDavid du Colombier 
9280ee5cbfSDavid du Colombier 	if((fd = open(file, ORDWR)) < 0) {
9380ee5cbfSDavid du Colombier 		if(access(file, AEXIST) == 0)
9480ee5cbfSDavid du Colombier 			return nil;
9580ee5cbfSDavid du Colombier 		return createcd(file, info);
9680ee5cbfSDavid du Colombier 	}
9780ee5cbfSDavid du Colombier 
989a747e4fSDavid du Colombier 	if((d = dirfstat(fd)) == nil) {
9980ee5cbfSDavid du Colombier 		close(fd);
10080ee5cbfSDavid du Colombier 		return nil;
10180ee5cbfSDavid du Colombier 	}
1029a747e4fSDavid du Colombier 	if(d->length == 0 || d->length % Blocksize) {
1039a747e4fSDavid du Colombier 		werrstr("bad length %lld", d->length);
10480ee5cbfSDavid du Colombier 		close(fd);
1059a747e4fSDavid du Colombier 		free(d);
10680ee5cbfSDavid du Colombier 		return nil;
10780ee5cbfSDavid du Colombier 	}
10880ee5cbfSDavid du Colombier 
10980ee5cbfSDavid du Colombier 	cd = emalloc(sizeof *cd);
11080ee5cbfSDavid du Colombier 	cd->file = atom(file);
1119a747e4fSDavid du Colombier 	cd->nextblock = d->length / Blocksize;
11280ee5cbfSDavid du Colombier 	assert(cd->nextblock != 0);
1139a747e4fSDavid du Colombier 	free(d);
11480ee5cbfSDavid du Colombier 
11580ee5cbfSDavid du Colombier 	Binit(&cd->brd, fd, OREAD);
11680ee5cbfSDavid du Colombier 
11780ee5cbfSDavid du Colombier 	if((xfd = open(file, ORDWR)) < 0)
11880ee5cbfSDavid du Colombier 		sysfatal("can't open file again: %r");
11980ee5cbfSDavid du Colombier 	Binit(&cd->bwr, xfd, OWRITE);
12080ee5cbfSDavid du Colombier 
12180ee5cbfSDavid du Colombier 	if(readisodesc(cd, &cd->iso) < 0) {
12280ee5cbfSDavid du Colombier 		free(cd);
12380ee5cbfSDavid du Colombier 		close(fd);
12480ee5cbfSDavid du Colombier 		close(xfd);
12580ee5cbfSDavid du Colombier 		return nil;
12680ee5cbfSDavid du Colombier 	}
12780ee5cbfSDavid du Colombier 
12880ee5cbfSDavid du Colombier 	/* lowercase because of isostring */
12980ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "iso9660") == nil
13080ee5cbfSDavid du Colombier 	&& strstr(cd->iso.systemid, "utf8") == nil) {
13180ee5cbfSDavid du Colombier 		werrstr("unknown systemid %s", cd->iso.systemid);
13280ee5cbfSDavid du Colombier 		free(cd);
13380ee5cbfSDavid du Colombier 		close(fd);
13480ee5cbfSDavid du Colombier 		close(xfd);
13580ee5cbfSDavid du Colombier 		return nil;
13680ee5cbfSDavid du Colombier 	}
13780ee5cbfSDavid du Colombier 
13880ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "plan 9"))
13980ee5cbfSDavid du Colombier 		cd->flags |= CDplan9;
14080ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "iso9660"))
14180ee5cbfSDavid du Colombier 		cd->flags |= CDconform;
14280ee5cbfSDavid du Colombier 	if(strstr(cd->iso.systemid, "rrip"))
14380ee5cbfSDavid du Colombier 		cd->flags |= CDrockridge;
1449a747e4fSDavid du Colombier 	if(strstr(cd->iso.systemid, "boot"))
1459a747e4fSDavid du Colombier 		cd->flags |= CDbootable;
14680ee5cbfSDavid du Colombier 	if(readjolietdesc(cd, &cd->joliet) == 0)
14780ee5cbfSDavid du Colombier 		cd->flags |= CDjoliet;
14880ee5cbfSDavid du Colombier 	if(hasdump(cd))
14980ee5cbfSDavid du Colombier 		cd->flags |= CDdump;
15080ee5cbfSDavid du Colombier 
15180ee5cbfSDavid du Colombier 	return cd;
15280ee5cbfSDavid du Colombier }
15380ee5cbfSDavid du Colombier 
15480ee5cbfSDavid du Colombier ulong
big(void * a,int n)15580ee5cbfSDavid du Colombier big(void *a, int n)
15680ee5cbfSDavid du Colombier {
15780ee5cbfSDavid du Colombier 	uchar *p;
15880ee5cbfSDavid du Colombier 	ulong v;
15980ee5cbfSDavid du Colombier 	int i;
16080ee5cbfSDavid du Colombier 
16180ee5cbfSDavid du Colombier 	p = a;
16280ee5cbfSDavid du Colombier 	v = 0;
16380ee5cbfSDavid du Colombier 	for(i=0; i<n; i++)
16480ee5cbfSDavid du Colombier 		v = (v<<8) | *p++;
16580ee5cbfSDavid du Colombier 	return v;
16680ee5cbfSDavid du Colombier }
16780ee5cbfSDavid du Colombier 
16880ee5cbfSDavid du Colombier ulong
little(void * a,int n)16980ee5cbfSDavid du Colombier little(void *a, int n)
17080ee5cbfSDavid du Colombier {
17180ee5cbfSDavid du Colombier 	uchar *p;
17280ee5cbfSDavid du Colombier 	ulong v;
17380ee5cbfSDavid du Colombier 	int i;
17480ee5cbfSDavid du Colombier 
17580ee5cbfSDavid du Colombier 	p = a;
17680ee5cbfSDavid du Colombier 	v = 0;
17780ee5cbfSDavid du Colombier 	for(i=0; i<n; i++)
17880ee5cbfSDavid du Colombier 		v |= (*p++<<(i*8));
17980ee5cbfSDavid du Colombier 	return v;
18080ee5cbfSDavid du Colombier }
18180ee5cbfSDavid du Colombier 
18280ee5cbfSDavid du Colombier void
Creadblock(Cdimg * cd,void * buf,ulong block,ulong len)18380ee5cbfSDavid du Colombier Creadblock(Cdimg *cd, void *buf, ulong block, ulong len)
18480ee5cbfSDavid du Colombier {
18580ee5cbfSDavid du Colombier 	assert(block != 0);	/* nothing useful there */
18680ee5cbfSDavid du Colombier 
18780ee5cbfSDavid du Colombier 	Bflush(&cd->bwr);
18873ee67a1SDavid du Colombier 	if(Bseek(&cd->brd, (vlong)block * Blocksize, 0) !=
18973ee67a1SDavid du Colombier 	    (vlong)block * Blocksize)
19080ee5cbfSDavid du Colombier 		sysfatal("error seeking to block %lud", block);
19180ee5cbfSDavid du Colombier 	if(Bread(&cd->brd, buf, len) != len)
19273ee67a1SDavid du Colombier 		sysfatal("error reading %lud bytes at block %lud: %r %lld",
19373ee67a1SDavid du Colombier 			len, block, Bseek(&cd->brd, 0, 2));
19480ee5cbfSDavid du Colombier }
19580ee5cbfSDavid du Colombier 
19680ee5cbfSDavid du Colombier int
parsedir(Cdimg * cd,Direc * d,uchar * buf,int len,char * (* cvtname)(uchar *,int))19780ee5cbfSDavid du Colombier parsedir(Cdimg *cd, Direc *d, uchar *buf, int len, char *(*cvtname)(uchar*, int))
19880ee5cbfSDavid du Colombier {
1999a747e4fSDavid du Colombier 	enum { NAMELEN = 28 };
20080ee5cbfSDavid du Colombier 	char name[NAMELEN];
20180ee5cbfSDavid du Colombier 	uchar *p;
20280ee5cbfSDavid du Colombier 	Cdir *c;
20380ee5cbfSDavid du Colombier 
20480ee5cbfSDavid du Colombier 	memset(d, 0, sizeof *d);
20580ee5cbfSDavid du Colombier 
20680ee5cbfSDavid du Colombier 	c = (Cdir*)buf;
20780ee5cbfSDavid du Colombier 
20880ee5cbfSDavid du Colombier 	if(c->len > len) {
20980ee5cbfSDavid du Colombier 		werrstr("buffer too small");
21080ee5cbfSDavid du Colombier 		return -1;
21180ee5cbfSDavid du Colombier 	}
21280ee5cbfSDavid du Colombier 
21380ee5cbfSDavid du Colombier 	if(c->namelen == 1 && c->name[0] == '\0')
21480ee5cbfSDavid du Colombier 		d->name = atom(".");
21580ee5cbfSDavid du Colombier 	else if(c->namelen == 1 && c->name[0] == '\001')
21680ee5cbfSDavid du Colombier 		d->name = atom("..");
21780ee5cbfSDavid du Colombier 	else if(cvtname)
21880ee5cbfSDavid du Colombier 		d->name = cvtname(c->name, c->namelen);
21980ee5cbfSDavid du Colombier 
22080ee5cbfSDavid du Colombier 	d->block = little(c->dloc, 4);
22180ee5cbfSDavid du Colombier 	d->length = little(c->dlen, 4);
22280ee5cbfSDavid du Colombier 
22380ee5cbfSDavid du Colombier 	if(c->flags & 2)
2249a747e4fSDavid du Colombier 		d->mode |= DMDIR;
22580ee5cbfSDavid du Colombier 
22680ee5cbfSDavid du Colombier /*BUG: do we really need to parse the plan 9 fields? */
22780ee5cbfSDavid du Colombier 	/* plan 9 use fields */
22880ee5cbfSDavid du Colombier 	if((cd->flags & CDplan9) && cvtname == isostring
22980ee5cbfSDavid du Colombier 	&& (c->namelen != 1 || c->name[0] > 1)) {
23080ee5cbfSDavid du Colombier 		p = buf+33+c->namelen;
23180ee5cbfSDavid du Colombier 		if((p-buf)&1)
23280ee5cbfSDavid du Colombier 			p++;
23380ee5cbfSDavid du Colombier 		assert(p < buf+c->len);
23480ee5cbfSDavid du Colombier 		assert(*p < NAMELEN);
23580ee5cbfSDavid du Colombier 		if(*p != 0) {
23680ee5cbfSDavid du Colombier 			memmove(name, p+1, *p);
23780ee5cbfSDavid du Colombier 			name[*p] = '\0';
23880ee5cbfSDavid du Colombier 			d->confname = d->name;
23980ee5cbfSDavid du Colombier 			d->name = atom(name);
24080ee5cbfSDavid du Colombier 		}
24180ee5cbfSDavid du Colombier 		p += *p+1;
24280ee5cbfSDavid du Colombier 		assert(*p < NAMELEN);
24380ee5cbfSDavid du Colombier 		memmove(name, p+1, *p);
24480ee5cbfSDavid du Colombier 		name[*p] = '\0';
24580ee5cbfSDavid du Colombier 		d->uid = atom(name);
24680ee5cbfSDavid du Colombier 		p += *p+1;
24780ee5cbfSDavid du Colombier 		assert(*p < NAMELEN);
24880ee5cbfSDavid du Colombier 		memmove(name, p+1, *p);
24980ee5cbfSDavid du Colombier 		name[*p] = '\0';
25080ee5cbfSDavid du Colombier 		d->gid = atom(name);
25180ee5cbfSDavid du Colombier 		p += *p+1;
25280ee5cbfSDavid du Colombier 		if((p-buf)&1)
25380ee5cbfSDavid du Colombier 			p++;
25480ee5cbfSDavid du Colombier 		d->mode = little(p, 4);
25580ee5cbfSDavid du Colombier 	}
25680ee5cbfSDavid du Colombier 
25780ee5cbfSDavid du Colombier 	// BUG: rock ridge extensions
25880ee5cbfSDavid du Colombier 	return 0;
25980ee5cbfSDavid du Colombier }
26080ee5cbfSDavid du Colombier 
26180ee5cbfSDavid du Colombier void
setroot(Cdimg * cd,ulong block,ulong dloc,ulong dlen)26280ee5cbfSDavid du Colombier setroot(Cdimg *cd, ulong block, ulong dloc, ulong dlen)
26380ee5cbfSDavid du Colombier {
26480ee5cbfSDavid du Colombier 	assert(block != 0);
26580ee5cbfSDavid du Colombier 
26673ee67a1SDavid du Colombier 	Cwseek(cd, (vlong)block * Blocksize + offsetof(Cvoldesc, rootdir[0]) +
26773ee67a1SDavid du Colombier 		offsetof(Cdir, dloc[0]));
26880ee5cbfSDavid du Colombier 	Cputn(cd, dloc, 4);
26980ee5cbfSDavid du Colombier 	Cputn(cd, dlen, 4);
27080ee5cbfSDavid du Colombier }
27180ee5cbfSDavid du Colombier 
27280ee5cbfSDavid du Colombier void
setvolsize(Cdimg * cd,uvlong block,ulong size)2733e33a36fSDavid du Colombier setvolsize(Cdimg *cd, uvlong block, ulong size)
27480ee5cbfSDavid du Colombier {
27580ee5cbfSDavid du Colombier 	assert(block != 0);
27680ee5cbfSDavid du Colombier 
2773e33a36fSDavid du Colombier 	Cwseek(cd, block * Blocksize + offsetof(Cvoldesc, volsize[0]));
278*a587111cSDavid du Colombier 	Cputn(cd, size, 4);			/* size in blocks */
27980ee5cbfSDavid du Colombier }
28080ee5cbfSDavid du Colombier 
28180ee5cbfSDavid du Colombier void
setpathtable(Cdimg * cd,ulong block,ulong sz,ulong lloc,ulong bloc)28280ee5cbfSDavid du Colombier setpathtable(Cdimg *cd, ulong block, ulong sz, ulong lloc, ulong bloc)
28380ee5cbfSDavid du Colombier {
28480ee5cbfSDavid du Colombier 	assert(block != 0);
28580ee5cbfSDavid du Colombier 
28673ee67a1SDavid du Colombier 	Cwseek(cd, (vlong)block * Blocksize + offsetof(Cvoldesc, pathsize[0]));
28780ee5cbfSDavid du Colombier 	Cputn(cd, sz, 4);
28880ee5cbfSDavid du Colombier 	Cputnl(cd, lloc, 4);
28980ee5cbfSDavid du Colombier 	Cputnl(cd, 0, 4);
29080ee5cbfSDavid du Colombier 	Cputnm(cd, bloc, 4);
29180ee5cbfSDavid du Colombier 	Cputnm(cd, 0, 4);
29273ee67a1SDavid du Colombier 	assert(Cwoffset(cd) == (vlong)block * Blocksize +
29373ee67a1SDavid du Colombier 		offsetof(Cvoldesc, rootdir[0]));
29480ee5cbfSDavid du Colombier }
29580ee5cbfSDavid du Colombier 
29680ee5cbfSDavid du Colombier 
29780ee5cbfSDavid du Colombier static void
parsedesc(Voldesc * v,Cvoldesc * cv,char * (* string)(uchar *,int))29880ee5cbfSDavid du Colombier parsedesc(Voldesc *v, Cvoldesc *cv, char *(*string)(uchar*, int))
29980ee5cbfSDavid du Colombier {
30080ee5cbfSDavid du Colombier 	v->systemid = string(cv->systemid, sizeof cv->systemid);
30180ee5cbfSDavid du Colombier 
30280ee5cbfSDavid du Colombier 	v->pathsize = little(cv->pathsize, 4);
30380ee5cbfSDavid du Colombier 	v->lpathloc = little(cv->lpathloc, 4);
30480ee5cbfSDavid du Colombier 	v->mpathloc = little(cv->mpathloc, 4);
30580ee5cbfSDavid du Colombier 
30680ee5cbfSDavid du Colombier 	v->volumeset = string(cv->volumeset, sizeof cv->volumeset);
30780ee5cbfSDavid du Colombier 	v->publisher = string(cv->publisher, sizeof cv->publisher);
30880ee5cbfSDavid du Colombier 	v->preparer = string(cv->preparer, sizeof cv->preparer);
30980ee5cbfSDavid du Colombier 	v->application = string(cv->application, sizeof cv->application);
31080ee5cbfSDavid du Colombier 
31180ee5cbfSDavid du Colombier 	v->abstract = string(cv->abstract, sizeof cv->abstract);
31280ee5cbfSDavid du Colombier 	v->biblio = string(cv->biblio, sizeof cv->biblio);
31380ee5cbfSDavid du Colombier 	v->notice = string(cv->notice, sizeof cv->notice);
31480ee5cbfSDavid du Colombier }
31580ee5cbfSDavid du Colombier 
31680ee5cbfSDavid du Colombier static int
readisodesc(Cdimg * cd,Voldesc * v)31780ee5cbfSDavid du Colombier readisodesc(Cdimg *cd, Voldesc *v)
31880ee5cbfSDavid du Colombier {
31980ee5cbfSDavid du Colombier 	static uchar magic[] = { 0x01, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
32080ee5cbfSDavid du Colombier 	Cvoldesc cv;
32180ee5cbfSDavid du Colombier 
32280ee5cbfSDavid du Colombier 	memset(v, 0, sizeof *v);
32380ee5cbfSDavid du Colombier 
32480ee5cbfSDavid du Colombier 	Creadblock(cd, &cv, 16, sizeof cv);
32580ee5cbfSDavid du Colombier 	if(memcmp(cv.magic, magic, sizeof magic) != 0) {
32680ee5cbfSDavid du Colombier 		werrstr("bad pvd magic");
32780ee5cbfSDavid du Colombier 		return -1;
32880ee5cbfSDavid du Colombier 	}
32980ee5cbfSDavid du Colombier 
33080ee5cbfSDavid du Colombier 	if(little(cv.blocksize, 2) != Blocksize) {
33180ee5cbfSDavid du Colombier 		werrstr("block size not %d", Blocksize);
33280ee5cbfSDavid du Colombier 		return -1;
33380ee5cbfSDavid du Colombier 	}
33480ee5cbfSDavid du Colombier 
33580ee5cbfSDavid du Colombier 	cd->iso9660pvd = 16;
33680ee5cbfSDavid du Colombier 	parsedesc(v, &cv, isostring);
33780ee5cbfSDavid du Colombier 
33880ee5cbfSDavid du Colombier 	return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, isostring);
33980ee5cbfSDavid du Colombier }
34080ee5cbfSDavid du Colombier 
34180ee5cbfSDavid du Colombier static int
readjolietdesc(Cdimg * cd,Voldesc * v)34280ee5cbfSDavid du Colombier readjolietdesc(Cdimg *cd, Voldesc *v)
34380ee5cbfSDavid du Colombier {
34480ee5cbfSDavid du Colombier 	int i;
34580ee5cbfSDavid du Colombier 	static uchar magic[] = { 0x02, 'C', 'D', '0', '0', '1', 0x01, 0x00 };
34680ee5cbfSDavid du Colombier 	Cvoldesc cv;
34780ee5cbfSDavid du Colombier 
34880ee5cbfSDavid du Colombier 	memset(v, 0, sizeof *v);
34980ee5cbfSDavid du Colombier 
35080ee5cbfSDavid du Colombier 	for(i=16; i<24; i++) {
35180ee5cbfSDavid du Colombier 		Creadblock(cd, &cv, i, sizeof cv);
35280ee5cbfSDavid du Colombier 		if(memcmp(cv.magic, magic, sizeof magic) != 0)
35380ee5cbfSDavid du Colombier 			continue;
35480ee5cbfSDavid du Colombier 		if(cv.charset[0] != 0x25 || cv.charset[1] != 0x2F
35580ee5cbfSDavid du Colombier 		|| (cv.charset[2] != 0x40 && cv.charset[2] != 0x43 && cv.charset[2] != 0x45))
35680ee5cbfSDavid du Colombier 			continue;
35780ee5cbfSDavid du Colombier 		break;
35880ee5cbfSDavid du Colombier 	}
35980ee5cbfSDavid du Colombier 
36080ee5cbfSDavid du Colombier 	if(i==24) {
36180ee5cbfSDavid du Colombier 		werrstr("could not find Joliet SVD");
36280ee5cbfSDavid du Colombier 		return -1;
36380ee5cbfSDavid du Colombier 	}
36480ee5cbfSDavid du Colombier 
36580ee5cbfSDavid du Colombier 	if(little(cv.blocksize, 2) != Blocksize) {
36680ee5cbfSDavid du Colombier 		werrstr("block size not %d", Blocksize);
36780ee5cbfSDavid du Colombier 		return -1;
36880ee5cbfSDavid du Colombier 	}
36980ee5cbfSDavid du Colombier 
37080ee5cbfSDavid du Colombier 	cd->jolietsvd = i;
37180ee5cbfSDavid du Colombier 	parsedesc(v, &cv, jolietstring);
37280ee5cbfSDavid du Colombier 
37380ee5cbfSDavid du Colombier 	return parsedir(cd, &v->root, cv.rootdir, sizeof cv.rootdir, jolietstring);
37480ee5cbfSDavid du Colombier }
37580ee5cbfSDavid du Colombier 
37680ee5cbfSDavid du Colombier /*
37780ee5cbfSDavid du Colombier  * CD image buffering routines.
37880ee5cbfSDavid du Colombier  */
37980ee5cbfSDavid du Colombier void
Cputc(Cdimg * cd,int c)38080ee5cbfSDavid du Colombier Cputc(Cdimg *cd, int c)
38180ee5cbfSDavid du Colombier {
38280ee5cbfSDavid du Colombier 	assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0);
38380ee5cbfSDavid du Colombier 
38480ee5cbfSDavid du Colombier if(Boffset(&cd->bwr) == 0x9962)
38580ee5cbfSDavid du Colombier if(c >= 256) abort();
38680ee5cbfSDavid du Colombier 	if(Bputc(&cd->bwr, c) < 0)
38780ee5cbfSDavid du Colombier 		sysfatal("Bputc: %r");
38880ee5cbfSDavid du Colombier 	Bflush(&cd->brd);
38980ee5cbfSDavid du Colombier }
39080ee5cbfSDavid du Colombier 
39180ee5cbfSDavid du Colombier void
Cputnl(Cdimg * cd,uvlong val,int size)3923e33a36fSDavid du Colombier Cputnl(Cdimg *cd, uvlong val, int size)
39380ee5cbfSDavid du Colombier {
39480ee5cbfSDavid du Colombier 	switch(size) {
39580ee5cbfSDavid du Colombier 	default:
3963e33a36fSDavid du Colombier 		sysfatal("bad size %d in Cputnl", size);
39780ee5cbfSDavid du Colombier 	case 2:
3983e33a36fSDavid du Colombier 		if(val >= (1<<16))
3993e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
4003e33a36fSDavid du Colombier 				val, size);
40180ee5cbfSDavid du Colombier 		Cputc(cd, val);
40280ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
40380ee5cbfSDavid du Colombier 		break;
40480ee5cbfSDavid du Colombier 	case 4:
4053e33a36fSDavid du Colombier 		if(val >= (1ULL<<32))
4063e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
4073e33a36fSDavid du Colombier 				val, size);
40880ee5cbfSDavid du Colombier 		Cputc(cd, val);
40980ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
41080ee5cbfSDavid du Colombier 		Cputc(cd, val>>16);
41180ee5cbfSDavid du Colombier 		Cputc(cd, val>>24);
41280ee5cbfSDavid du Colombier 		break;
4133e33a36fSDavid du Colombier 	case 8:
4143e33a36fSDavid du Colombier 		Cputc(cd, val);
4153e33a36fSDavid du Colombier 		Cputc(cd, val>>8);
4163e33a36fSDavid du Colombier 		Cputc(cd, val>>16);
4173e33a36fSDavid du Colombier 		Cputc(cd, val>>24);
4183e33a36fSDavid du Colombier 		Cputc(cd, val>>32);
4193e33a36fSDavid du Colombier 		Cputc(cd, val>>40);
4203e33a36fSDavid du Colombier 		Cputc(cd, val>>48);
4213e33a36fSDavid du Colombier 		Cputc(cd, val>>56);
4223e33a36fSDavid du Colombier 		break;
42380ee5cbfSDavid du Colombier 	}
42480ee5cbfSDavid du Colombier }
42580ee5cbfSDavid du Colombier 
42680ee5cbfSDavid du Colombier void
Cputnm(Cdimg * cd,uvlong val,int size)4273e33a36fSDavid du Colombier Cputnm(Cdimg *cd, uvlong val, int size)
42880ee5cbfSDavid du Colombier {
42980ee5cbfSDavid du Colombier 	switch(size) {
43080ee5cbfSDavid du Colombier 	default:
4313e33a36fSDavid du Colombier 		sysfatal("bad size %d in Cputnm", size);
43280ee5cbfSDavid du Colombier 	case 2:
4333e33a36fSDavid du Colombier 		if(val >= (1<<16))
4343e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
4353e33a36fSDavid du Colombier 				val, size);
43680ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
43780ee5cbfSDavid du Colombier 		Cputc(cd, val);
43880ee5cbfSDavid du Colombier 		break;
43980ee5cbfSDavid du Colombier 	case 4:
4403e33a36fSDavid du Colombier 		if(val >= (1ULL<<32))
4413e33a36fSDavid du Colombier 			sysfatal("value %llud too big for size %d in Cputnl",
4423e33a36fSDavid du Colombier 				val, size);
4433e33a36fSDavid du Colombier 		Cputc(cd, val>>24);
4443e33a36fSDavid du Colombier 		Cputc(cd, val>>16);
4453e33a36fSDavid du Colombier 		Cputc(cd, val>>8);
4463e33a36fSDavid du Colombier 		Cputc(cd, val);
4473e33a36fSDavid du Colombier 		break;
4483e33a36fSDavid du Colombier 	case 8:
4493e33a36fSDavid du Colombier 		Cputc(cd, val>>56);
4503e33a36fSDavid du Colombier 		Cputc(cd, val>>48);
4513e33a36fSDavid du Colombier 		Cputc(cd, val>>40);
4523e33a36fSDavid du Colombier 		Cputc(cd, val>>32);
45380ee5cbfSDavid du Colombier 		Cputc(cd, val>>24);
45480ee5cbfSDavid du Colombier 		Cputc(cd, val>>16);
45580ee5cbfSDavid du Colombier 		Cputc(cd, val>>8);
45680ee5cbfSDavid du Colombier 		Cputc(cd, val);
45780ee5cbfSDavid du Colombier 		break;
45880ee5cbfSDavid du Colombier 	}
45980ee5cbfSDavid du Colombier }
46080ee5cbfSDavid du Colombier 
46180ee5cbfSDavid du Colombier void
Cputn(Cdimg * cd,uvlong val,int size)4623e33a36fSDavid du Colombier Cputn(Cdimg *cd, uvlong val, int size)
46380ee5cbfSDavid du Colombier {
46480ee5cbfSDavid du Colombier 	Cputnl(cd, val, size);
46580ee5cbfSDavid du Colombier 	Cputnm(cd, val, size);
46680ee5cbfSDavid du Colombier }
46780ee5cbfSDavid du Colombier 
46880ee5cbfSDavid du Colombier /*
46980ee5cbfSDavid du Colombier  * ASCII/UTF string writing
47080ee5cbfSDavid du Colombier  */
47180ee5cbfSDavid du Colombier void
Crepeat(Cdimg * cd,int c,int n)47280ee5cbfSDavid du Colombier Crepeat(Cdimg *cd, int c, int n)
47380ee5cbfSDavid du Colombier {
47480ee5cbfSDavid du Colombier 	while(n-- > 0)
47580ee5cbfSDavid du Colombier 		Cputc(cd, c);
47680ee5cbfSDavid du Colombier }
47780ee5cbfSDavid du Colombier 
47880ee5cbfSDavid du Colombier void
Cputs(Cdimg * cd,char * s,int size)47980ee5cbfSDavid du Colombier Cputs(Cdimg *cd, char *s, int size)
48080ee5cbfSDavid du Colombier {
48180ee5cbfSDavid du Colombier 	int n;
48280ee5cbfSDavid du Colombier 
48380ee5cbfSDavid du Colombier 	if(s == nil) {
48480ee5cbfSDavid du Colombier 		Crepeat(cd, ' ', size);
48580ee5cbfSDavid du Colombier 		return;
48680ee5cbfSDavid du Colombier 	}
48780ee5cbfSDavid du Colombier 
48880ee5cbfSDavid du Colombier 	for(n=0; n<size && *s; n++)
48980ee5cbfSDavid du Colombier 		Cputc(cd, *s++);
49080ee5cbfSDavid du Colombier 	if(n<size)
49180ee5cbfSDavid du Colombier 		Crepeat(cd, ' ', size-n);
49280ee5cbfSDavid du Colombier }
49380ee5cbfSDavid du Colombier 
49480ee5cbfSDavid du Colombier void
Cwrite(Cdimg * cd,void * buf,int n)49580ee5cbfSDavid du Colombier Cwrite(Cdimg *cd, void *buf, int n)
49680ee5cbfSDavid du Colombier {
49780ee5cbfSDavid du Colombier 	assert(Boffset(&cd->bwr) >= 16*Blocksize);
49880ee5cbfSDavid du Colombier 
49980ee5cbfSDavid du Colombier 	if(Bwrite(&cd->bwr, buf, n) != n)
50080ee5cbfSDavid du Colombier 		sysfatal("Bwrite: %r");
50180ee5cbfSDavid du Colombier 	Bflush(&cd->brd);
50280ee5cbfSDavid du Colombier }
50380ee5cbfSDavid du Colombier 
50480ee5cbfSDavid du Colombier void
Cputr(Cdimg * cd,Rune r)50580ee5cbfSDavid du Colombier Cputr(Cdimg *cd, Rune r)
50680ee5cbfSDavid du Colombier {
50780ee5cbfSDavid du Colombier 	Cputc(cd, r>>8);
50880ee5cbfSDavid du Colombier 	Cputc(cd, r);
50980ee5cbfSDavid du Colombier }
51080ee5cbfSDavid du Colombier 
51180ee5cbfSDavid du Colombier void
Crepeatr(Cdimg * cd,Rune r,int n)51280ee5cbfSDavid du Colombier Crepeatr(Cdimg *cd, Rune r, int n)
51380ee5cbfSDavid du Colombier {
51480ee5cbfSDavid du Colombier 	int i;
51580ee5cbfSDavid du Colombier 
51680ee5cbfSDavid du Colombier 	for(i=0; i<n; i++)
51780ee5cbfSDavid du Colombier 		Cputr(cd, r);
51880ee5cbfSDavid du Colombier }
51980ee5cbfSDavid du Colombier 
52080ee5cbfSDavid du Colombier void
Cputrs(Cdimg * cd,Rune * s,int osize)52180ee5cbfSDavid du Colombier Cputrs(Cdimg *cd, Rune *s, int osize)
52280ee5cbfSDavid du Colombier {
52380ee5cbfSDavid du Colombier 	int n, size;
52480ee5cbfSDavid du Colombier 
52580ee5cbfSDavid du Colombier 	size = osize/2;
52680ee5cbfSDavid du Colombier 	if(s == nil)
52780ee5cbfSDavid du Colombier 		Crepeatr(cd, (Rune)' ', size);
52880ee5cbfSDavid du Colombier 	else {
52980ee5cbfSDavid du Colombier 		for(n=0; *s && n<size; n++)
53080ee5cbfSDavid du Colombier 			Cputr(cd, *s++);
53180ee5cbfSDavid du Colombier 		if(n<size)
53280ee5cbfSDavid du Colombier 			Crepeatr(cd, ' ', size-n);
53380ee5cbfSDavid du Colombier 	}
53480ee5cbfSDavid du Colombier 	if(osize&1)
53580ee5cbfSDavid du Colombier 		Cputc(cd, 0);	/* what else can we do? */
53680ee5cbfSDavid du Colombier }
53780ee5cbfSDavid du Colombier 
53880ee5cbfSDavid du Colombier void
Cputrscvt(Cdimg * cd,char * s,int size)53980ee5cbfSDavid du Colombier Cputrscvt(Cdimg *cd, char *s, int size)
54080ee5cbfSDavid du Colombier {
54180ee5cbfSDavid du Colombier 	Rune r[256];
54280ee5cbfSDavid du Colombier 
54380ee5cbfSDavid du Colombier 	strtorune(r, s);
54480ee5cbfSDavid du Colombier 	Cputrs(cd, strtorune(r, s), size);
54580ee5cbfSDavid du Colombier }
54680ee5cbfSDavid du Colombier 
54780ee5cbfSDavid du Colombier void
Cpadblock(Cdimg * cd)54880ee5cbfSDavid du Colombier Cpadblock(Cdimg *cd)
54980ee5cbfSDavid du Colombier {
55080ee5cbfSDavid du Colombier 	int n;
55180ee5cbfSDavid du Colombier 	ulong nb;
55280ee5cbfSDavid du Colombier 
55380ee5cbfSDavid du Colombier 	n = Blocksize - (Boffset(&cd->bwr) % Blocksize);
55480ee5cbfSDavid du Colombier 	if(n != Blocksize)
55580ee5cbfSDavid du Colombier 		Crepeat(cd, 0, n);
55680ee5cbfSDavid du Colombier 
55780ee5cbfSDavid du Colombier 	nb = Boffset(&cd->bwr)/Blocksize;
55880ee5cbfSDavid du Colombier 	assert(nb != 0);
55980ee5cbfSDavid du Colombier 	if(nb > cd->nextblock)
56080ee5cbfSDavid du Colombier 		cd->nextblock = nb;
56180ee5cbfSDavid du Colombier }
56280ee5cbfSDavid du Colombier 
56380ee5cbfSDavid du Colombier void
Cputdate(Cdimg * cd,ulong ust)56480ee5cbfSDavid du Colombier Cputdate(Cdimg *cd, ulong ust)
56580ee5cbfSDavid du Colombier {
56680ee5cbfSDavid du Colombier 	Tm *tm;
56780ee5cbfSDavid du Colombier 
56880ee5cbfSDavid du Colombier 	if(ust == 0) {
56980ee5cbfSDavid du Colombier 		Crepeat(cd, 0, 7);
57080ee5cbfSDavid du Colombier 		return;
57180ee5cbfSDavid du Colombier 	}
57280ee5cbfSDavid du Colombier 	tm = gmtime(ust);
57380ee5cbfSDavid du Colombier 	Cputc(cd, tm->year);
57480ee5cbfSDavid du Colombier 	Cputc(cd, tm->mon+1);
57580ee5cbfSDavid du Colombier 	Cputc(cd, tm->mday);
57680ee5cbfSDavid du Colombier 	Cputc(cd, tm->hour);
57780ee5cbfSDavid du Colombier 	Cputc(cd, tm->min);
57880ee5cbfSDavid du Colombier 	Cputc(cd, tm->sec);
57980ee5cbfSDavid du Colombier 	Cputc(cd, 0);
58080ee5cbfSDavid du Colombier }
58180ee5cbfSDavid du Colombier 
58280ee5cbfSDavid du Colombier void
Cputdate1(Cdimg * cd,ulong ust)58380ee5cbfSDavid du Colombier Cputdate1(Cdimg *cd, ulong ust)
58480ee5cbfSDavid du Colombier {
58580ee5cbfSDavid du Colombier 	Tm *tm;
58680ee5cbfSDavid du Colombier 	char str[20];
58780ee5cbfSDavid du Colombier 
58880ee5cbfSDavid du Colombier 	if(ust == 0) {
58980ee5cbfSDavid du Colombier 		Crepeat(cd, '0', 16);
59080ee5cbfSDavid du Colombier 		Cputc(cd, 0);
59180ee5cbfSDavid du Colombier 		return;
59280ee5cbfSDavid du Colombier 	}
59380ee5cbfSDavid du Colombier 	tm = gmtime(ust);
59480ee5cbfSDavid du Colombier 	sprint(str, "%.4d%.2d%.2d%.2d%.2d%.4d",
59580ee5cbfSDavid du Colombier 		tm->year+1900,
59680ee5cbfSDavid du Colombier 		tm->mon+1,
59780ee5cbfSDavid du Colombier 		tm->mday,
59880ee5cbfSDavid du Colombier 		tm->hour,
59980ee5cbfSDavid du Colombier 		tm->min,
60080ee5cbfSDavid du Colombier 		tm->sec*100);
60180ee5cbfSDavid du Colombier 	Cputs(cd, str, 16);
60280ee5cbfSDavid du Colombier 	Cputc(cd, 0);
60380ee5cbfSDavid du Colombier }
60480ee5cbfSDavid du Colombier 
60580ee5cbfSDavid du Colombier void
Cwseek(Cdimg * cd,vlong offset)60673ee67a1SDavid du Colombier Cwseek(Cdimg *cd, vlong offset)
60780ee5cbfSDavid du Colombier {
60880ee5cbfSDavid du Colombier 	Bseek(&cd->bwr, offset, 0);
60980ee5cbfSDavid du Colombier }
61080ee5cbfSDavid du Colombier 
61173ee67a1SDavid du Colombier uvlong
Cwoffset(Cdimg * cd)61280ee5cbfSDavid du Colombier Cwoffset(Cdimg *cd)
61380ee5cbfSDavid du Colombier {
61480ee5cbfSDavid du Colombier 	return Boffset(&cd->bwr);
61580ee5cbfSDavid du Colombier }
61680ee5cbfSDavid du Colombier 
61780ee5cbfSDavid du Colombier void
Cwflush(Cdimg * cd)61880ee5cbfSDavid du Colombier Cwflush(Cdimg *cd)
61980ee5cbfSDavid du Colombier {
62080ee5cbfSDavid du Colombier 	Bflush(&cd->bwr);
62180ee5cbfSDavid du Colombier }
62280ee5cbfSDavid du Colombier 
62373ee67a1SDavid du Colombier uvlong
Croffset(Cdimg * cd)62480ee5cbfSDavid du Colombier Croffset(Cdimg *cd)
62580ee5cbfSDavid du Colombier {
62680ee5cbfSDavid du Colombier 	return Boffset(&cd->brd);
62780ee5cbfSDavid du Colombier }
62880ee5cbfSDavid du Colombier 
62980ee5cbfSDavid du Colombier void
Crseek(Cdimg * cd,vlong offset)63073ee67a1SDavid du Colombier Crseek(Cdimg *cd, vlong offset)
63180ee5cbfSDavid du Colombier {
63280ee5cbfSDavid du Colombier 	Bseek(&cd->brd, offset, 0);
63380ee5cbfSDavid du Colombier }
63480ee5cbfSDavid du Colombier 
63580ee5cbfSDavid du Colombier int
Cgetc(Cdimg * cd)63680ee5cbfSDavid du Colombier Cgetc(Cdimg *cd)
63780ee5cbfSDavid du Colombier {
63880ee5cbfSDavid du Colombier 	int c;
63980ee5cbfSDavid du Colombier 
64080ee5cbfSDavid du Colombier 	Cwflush(cd);
64180ee5cbfSDavid du Colombier 	if((c = Bgetc(&cd->brd)) == Beof) {
64273ee67a1SDavid du Colombier 		fprint(2, "getc at %llud\n", Croffset(cd));
64380ee5cbfSDavid du Colombier 		assert(0);
64480ee5cbfSDavid du Colombier 		//sysfatal("Bgetc: %r");
64580ee5cbfSDavid du Colombier 	}
64680ee5cbfSDavid du Colombier 	return c;
64780ee5cbfSDavid du Colombier }
64880ee5cbfSDavid du Colombier 
64980ee5cbfSDavid du Colombier void
Cread(Cdimg * cd,void * buf,int n)65080ee5cbfSDavid du Colombier Cread(Cdimg *cd, void *buf, int n)
65180ee5cbfSDavid du Colombier {
65280ee5cbfSDavid du Colombier 	Cwflush(cd);
65380ee5cbfSDavid du Colombier 	if(Bread(&cd->brd, buf, n) != n)
65480ee5cbfSDavid du Colombier 		sysfatal("Bread: %r");
65580ee5cbfSDavid du Colombier }
65680ee5cbfSDavid du Colombier 
65780ee5cbfSDavid du Colombier char*
Crdline(Cdimg * cd,int c)65880ee5cbfSDavid du Colombier Crdline(Cdimg *cd, int c)
65980ee5cbfSDavid du Colombier {
66080ee5cbfSDavid du Colombier 	Cwflush(cd);
66180ee5cbfSDavid du Colombier 	return Brdline(&cd->brd, c);
66280ee5cbfSDavid du Colombier }
66380ee5cbfSDavid du Colombier 
66480ee5cbfSDavid du Colombier int
Clinelen(Cdimg * cd)66580ee5cbfSDavid du Colombier Clinelen(Cdimg *cd)
66680ee5cbfSDavid du Colombier {
66780ee5cbfSDavid du Colombier 	return Blinelen(&cd->brd);
66880ee5cbfSDavid du Colombier }
66980ee5cbfSDavid du Colombier 
670