xref: /plan9/sys/src/cmd/disk/9660/path.c (revision 73ee67a1775bb9176ad6f77775e030678f092526)
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 /*
980ee5cbfSDavid du Colombier  * Add the requisite path tables to the CD image.
1080ee5cbfSDavid du Colombier  * They get put on the end once everything else is done.
1180ee5cbfSDavid du Colombier  * We use the path table itself as a queue in the breadth-first
1280ee5cbfSDavid du Colombier  * traversal of the tree.
1380ee5cbfSDavid du Colombier  *
1480ee5cbfSDavid du Colombier  * The only problem with this is that the path table does not
1580ee5cbfSDavid du Colombier  * store the lengths of the directories.  So we keep an explicit
1680ee5cbfSDavid du Colombier  * map in an array in memory.
1780ee5cbfSDavid du Colombier  */
1880ee5cbfSDavid du Colombier 
1980ee5cbfSDavid du Colombier enum {
2080ee5cbfSDavid du Colombier 	Big,
2180ee5cbfSDavid du Colombier 	Little
2280ee5cbfSDavid du Colombier };
2380ee5cbfSDavid du Colombier 
2480ee5cbfSDavid du Colombier static void
Crdpath(Cdimg * cd,Cpath * p)2580ee5cbfSDavid du Colombier Crdpath(Cdimg *cd, Cpath *p)
2680ee5cbfSDavid du Colombier {
2780ee5cbfSDavid du Colombier 	p->namelen = Cgetc(cd);
2880ee5cbfSDavid du Colombier 	if(p->namelen == 0) {
2980ee5cbfSDavid du Colombier 		Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize);
3080ee5cbfSDavid du Colombier 		p->namelen = Cgetc(cd);
3180ee5cbfSDavid du Colombier 		assert(p->namelen != 0);
3280ee5cbfSDavid du Colombier 	}
3380ee5cbfSDavid du Colombier 
3480ee5cbfSDavid du Colombier 	p->xlen = Cgetc(cd);
3580ee5cbfSDavid du Colombier 	assert(p->xlen == 0);	/* sanity, might not be true if we start using the extended fields */
3680ee5cbfSDavid du Colombier 
3780ee5cbfSDavid du Colombier 	Cread(cd, p->dloc, 4);
3880ee5cbfSDavid du Colombier 	Cread(cd, p->parent, 2);
3980ee5cbfSDavid du Colombier 	p->name[0] = '\0';
4080ee5cbfSDavid du Colombier 	Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1));	/* skip name, ext data */
4180ee5cbfSDavid du Colombier }
4280ee5cbfSDavid du Colombier 
4380ee5cbfSDavid du Colombier static void
writepath(Cdimg * cd,Cdir * c,int parent,int size)4480ee5cbfSDavid du Colombier writepath(Cdimg *cd, Cdir *c, int parent, int size)
4580ee5cbfSDavid du Colombier {
465d459b5aSDavid du Colombier /*
475d459b5aSDavid du Colombier 	DO NOT UNCOMMENT THIS CODE.
485d459b5aSDavid du Colombier 	This commented-out code is here only so that no one comes
495d459b5aSDavid du Colombier 	along and adds it later.
505d459b5aSDavid du Colombier 
515d459b5aSDavid du Colombier 	The ISO 9660 spec is silent about whether path table entries
525d459b5aSDavid du Colombier 	need to be padded so that they never cross block boundaries.
535d459b5aSDavid du Colombier 	It would be reasonable to assume that they are like every other
545d459b5aSDavid du Colombier 	data structure in the bloody spec; this code pads them out.
555d459b5aSDavid du Colombier 
565d459b5aSDavid du Colombier 	Empirically, though, they're NOT padded.  Windows NT and
575d459b5aSDavid du Colombier 	derivatives are the only known current operating systems
585d459b5aSDavid du Colombier 	that actually read these things.
595d459b5aSDavid du Colombier 
6080ee5cbfSDavid du Colombier 	int l;
6180ee5cbfSDavid du Colombier 
6280ee5cbfSDavid du Colombier 	l = 1+1+4+2+c->namelen;
6380ee5cbfSDavid du Colombier 	if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize)
6480ee5cbfSDavid du Colombier 		Cpadblock(cd);
655d459b5aSDavid du Colombier */
6680ee5cbfSDavid du Colombier 	Cputc(cd, c->namelen);
6780ee5cbfSDavid du Colombier 	Cputc(cd, 0);
6880ee5cbfSDavid du Colombier 	Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4);
6980ee5cbfSDavid du Colombier 	(size==Little ? Cputnl : Cputnm)(cd, parent, 2);
7080ee5cbfSDavid du Colombier 	Cwrite(cd, c->name, c->namelen);
7180ee5cbfSDavid du Colombier 	if(c->namelen & 1)
7280ee5cbfSDavid du Colombier 		Cputc(cd, 0);
7380ee5cbfSDavid du Colombier }
7480ee5cbfSDavid du Colombier 
7580ee5cbfSDavid du Colombier static ulong*
addlength(ulong * a,ulong x,int n)7680ee5cbfSDavid du Colombier addlength(ulong *a, ulong x, int n)
7780ee5cbfSDavid du Colombier {
7880ee5cbfSDavid du Colombier 	if(n%128==0)
7980ee5cbfSDavid du Colombier 		a = erealloc(a, (n+128)*sizeof a[0]);
8080ee5cbfSDavid du Colombier 	a[n] = x;
8180ee5cbfSDavid du Colombier 	return a;
8280ee5cbfSDavid du Colombier }
8380ee5cbfSDavid du Colombier 
8480ee5cbfSDavid du Colombier static ulong
writepathtable(Cdimg * cd,ulong vdblock,int size)8580ee5cbfSDavid du Colombier writepathtable(Cdimg *cd, ulong vdblock, int size)
8680ee5cbfSDavid du Colombier {
8780ee5cbfSDavid du Colombier 	int rp, wp;
8880ee5cbfSDavid du Colombier 	uchar buf[Blocksize];
89*73ee67a1SDavid du Colombier 	ulong bk, i, *len, n;
90*73ee67a1SDavid du Colombier 	uvlong start, end, rdoff;
9180ee5cbfSDavid du Colombier 	Cdir *c;
9280ee5cbfSDavid du Colombier 	Cpath p;
9380ee5cbfSDavid du Colombier 
9480ee5cbfSDavid du Colombier 	Creadblock(cd, buf, vdblock, Blocksize);
9580ee5cbfSDavid du Colombier 	c = (Cdir*)(buf + offsetof(Cvoldesc, rootdir[0]));
9680ee5cbfSDavid du Colombier 
9780ee5cbfSDavid du Colombier 	rp = 0;
9880ee5cbfSDavid du Colombier 	wp = 0;
9980ee5cbfSDavid du Colombier 	len = nil;
100*73ee67a1SDavid du Colombier 	start = (vlong)cd->nextblock * Blocksize;
10180ee5cbfSDavid du Colombier 	Cwseek(cd, start);
10280ee5cbfSDavid du Colombier 	Crseek(cd, start);
10380ee5cbfSDavid du Colombier 	writepath(cd, c, 1, size);
10480ee5cbfSDavid du Colombier 	len = addlength(len, little(c->dlen, 4), wp);
10580ee5cbfSDavid du Colombier 	wp++;
10680ee5cbfSDavid du Colombier 
10780ee5cbfSDavid du Colombier 	while(rp < wp) {
10880ee5cbfSDavid du Colombier 		Crdpath(cd, &p);
10980ee5cbfSDavid du Colombier 		n = (len[rp]+Blocksize-1)/Blocksize;
11080ee5cbfSDavid du Colombier 		rp++;
11180ee5cbfSDavid du Colombier 		bk = (size==Big ? big : little)(p.dloc, 4);
11280ee5cbfSDavid du Colombier 		rdoff = Croffset(cd);
11380ee5cbfSDavid du Colombier 		for(i=0; i<n; i++) {
11480ee5cbfSDavid du Colombier 			Creadblock(cd, buf, bk+i, Blocksize);
11580ee5cbfSDavid du Colombier 			c = (Cdir*)buf;
116*73ee67a1SDavid du Colombier 			if(i != 0 && c->namelen == 1 && c->name[0] == '\0')
117*73ee67a1SDavid du Colombier 				break;	/* hit another directory; stop */
118*73ee67a1SDavid du Colombier 			while(c->len && c->namelen &&
119*73ee67a1SDavid du Colombier 			    (uchar*)c + c->len < buf + Blocksize) {
120*73ee67a1SDavid du Colombier 				if(c->flags & 0x02 &&
121*73ee67a1SDavid du Colombier 				    (c->namelen > 1 || c->name[0] > '\001')) {
122*73ee67a1SDavid du Colombier 					/* directory */
12380ee5cbfSDavid du Colombier 					writepath(cd, c, rp, size);
12480ee5cbfSDavid du Colombier 					len = addlength(len, little(c->dlen, 4), wp);
12580ee5cbfSDavid du Colombier 					wp++;
12680ee5cbfSDavid du Colombier 				}
12780ee5cbfSDavid du Colombier 				c = (Cdir*)((uchar*)c+c->len);
12880ee5cbfSDavid du Colombier 			}
12980ee5cbfSDavid du Colombier 		}
13080ee5cbfSDavid du Colombier 		Crseek(cd, rdoff);
13180ee5cbfSDavid du Colombier 	}
13280ee5cbfSDavid du Colombier 	end = Cwoffset(cd);
13380ee5cbfSDavid du Colombier 	Cpadblock(cd);
13480ee5cbfSDavid du Colombier 	return end-start;
13580ee5cbfSDavid du Colombier }
13680ee5cbfSDavid du Colombier 
13780ee5cbfSDavid du Colombier 
13880ee5cbfSDavid du Colombier static void
writepathtablepair(Cdimg * cd,ulong vdblock)13980ee5cbfSDavid du Colombier writepathtablepair(Cdimg *cd, ulong vdblock)
14080ee5cbfSDavid du Colombier {
14180ee5cbfSDavid du Colombier 	ulong bloc, lloc, sz, sz2;
14280ee5cbfSDavid du Colombier 
14380ee5cbfSDavid du Colombier 	lloc = cd->nextblock;
14480ee5cbfSDavid du Colombier 	sz = writepathtable(cd, vdblock, Little);
14580ee5cbfSDavid du Colombier 	bloc = cd->nextblock;
14680ee5cbfSDavid du Colombier 	sz2 = writepathtable(cd, vdblock, Big);
14780ee5cbfSDavid du Colombier 	assert(sz == sz2);
14880ee5cbfSDavid du Colombier 	setpathtable(cd, vdblock, sz, lloc, bloc);
14980ee5cbfSDavid du Colombier }
15080ee5cbfSDavid du Colombier 
15180ee5cbfSDavid du Colombier void
writepathtables(Cdimg * cd)15280ee5cbfSDavid du Colombier writepathtables(Cdimg *cd)
15380ee5cbfSDavid du Colombier {
15480ee5cbfSDavid du Colombier 	cd->pathblock = cd->nextblock;
15580ee5cbfSDavid du Colombier 
15680ee5cbfSDavid du Colombier 	writepathtablepair(cd, cd->iso9660pvd);
15780ee5cbfSDavid du Colombier 	if(cd->flags & CDjoliet)
15880ee5cbfSDavid du Colombier 		writepathtablepair(cd, cd->jolietsvd);
15980ee5cbfSDavid du Colombier }
160