xref: /plan9/sys/src/cmd/disk/9660/path.c (revision 73ee67a1775bb9176ad6f77775e030678f092526)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <libsec.h>
5 
6 #include "iso9660.h"
7 
8 /*
9  * Add the requisite path tables to the CD image.
10  * They get put on the end once everything else is done.
11  * We use the path table itself as a queue in the breadth-first
12  * traversal of the tree.
13  *
14  * The only problem with this is that the path table does not
15  * store the lengths of the directories.  So we keep an explicit
16  * map in an array in memory.
17  */
18 
19 enum {
20 	Big,
21 	Little
22 };
23 
24 static void
Crdpath(Cdimg * cd,Cpath * p)25 Crdpath(Cdimg *cd, Cpath *p)
26 {
27 	p->namelen = Cgetc(cd);
28 	if(p->namelen == 0) {
29 		Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize);
30 		p->namelen = Cgetc(cd);
31 		assert(p->namelen != 0);
32 	}
33 
34 	p->xlen = Cgetc(cd);
35 	assert(p->xlen == 0);	/* sanity, might not be true if we start using the extended fields */
36 
37 	Cread(cd, p->dloc, 4);
38 	Cread(cd, p->parent, 2);
39 	p->name[0] = '\0';
40 	Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1));	/* skip name, ext data */
41 }
42 
43 static void
writepath(Cdimg * cd,Cdir * c,int parent,int size)44 writepath(Cdimg *cd, Cdir *c, int parent, int size)
45 {
46 /*
47 	DO NOT UNCOMMENT THIS CODE.
48 	This commented-out code is here only so that no one comes
49 	along and adds it later.
50 
51 	The ISO 9660 spec is silent about whether path table entries
52 	need to be padded so that they never cross block boundaries.
53 	It would be reasonable to assume that they are like every other
54 	data structure in the bloody spec; this code pads them out.
55 
56 	Empirically, though, they're NOT padded.  Windows NT and
57 	derivatives are the only known current operating systems
58 	that actually read these things.
59 
60 	int l;
61 
62 	l = 1+1+4+2+c->namelen;
63 	if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize)
64 		Cpadblock(cd);
65 */
66 	Cputc(cd, c->namelen);
67 	Cputc(cd, 0);
68 	Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4);
69 	(size==Little ? Cputnl : Cputnm)(cd, parent, 2);
70 	Cwrite(cd, c->name, c->namelen);
71 	if(c->namelen & 1)
72 		Cputc(cd, 0);
73 }
74 
75 static ulong*
addlength(ulong * a,ulong x,int n)76 addlength(ulong *a, ulong x, int n)
77 {
78 	if(n%128==0)
79 		a = erealloc(a, (n+128)*sizeof a[0]);
80 	a[n] = x;
81 	return a;
82 }
83 
84 static ulong
writepathtable(Cdimg * cd,ulong vdblock,int size)85 writepathtable(Cdimg *cd, ulong vdblock, int size)
86 {
87 	int rp, wp;
88 	uchar buf[Blocksize];
89 	ulong bk, i, *len, n;
90 	uvlong start, end, rdoff;
91 	Cdir *c;
92 	Cpath p;
93 
94 	Creadblock(cd, buf, vdblock, Blocksize);
95 	c = (Cdir*)(buf + offsetof(Cvoldesc, rootdir[0]));
96 
97 	rp = 0;
98 	wp = 0;
99 	len = nil;
100 	start = (vlong)cd->nextblock * Blocksize;
101 	Cwseek(cd, start);
102 	Crseek(cd, start);
103 	writepath(cd, c, 1, size);
104 	len = addlength(len, little(c->dlen, 4), wp);
105 	wp++;
106 
107 	while(rp < wp) {
108 		Crdpath(cd, &p);
109 		n = (len[rp]+Blocksize-1)/Blocksize;
110 		rp++;
111 		bk = (size==Big ? big : little)(p.dloc, 4);
112 		rdoff = Croffset(cd);
113 		for(i=0; i<n; i++) {
114 			Creadblock(cd, buf, bk+i, Blocksize);
115 			c = (Cdir*)buf;
116 			if(i != 0 && c->namelen == 1 && c->name[0] == '\0')
117 				break;	/* hit another directory; stop */
118 			while(c->len && c->namelen &&
119 			    (uchar*)c + c->len < buf + Blocksize) {
120 				if(c->flags & 0x02 &&
121 				    (c->namelen > 1 || c->name[0] > '\001')) {
122 					/* directory */
123 					writepath(cd, c, rp, size);
124 					len = addlength(len, little(c->dlen, 4), wp);
125 					wp++;
126 				}
127 				c = (Cdir*)((uchar*)c+c->len);
128 			}
129 		}
130 		Crseek(cd, rdoff);
131 	}
132 	end = Cwoffset(cd);
133 	Cpadblock(cd);
134 	return end-start;
135 }
136 
137 
138 static void
writepathtablepair(Cdimg * cd,ulong vdblock)139 writepathtablepair(Cdimg *cd, ulong vdblock)
140 {
141 	ulong bloc, lloc, sz, sz2;
142 
143 	lloc = cd->nextblock;
144 	sz = writepathtable(cd, vdblock, Little);
145 	bloc = cd->nextblock;
146 	sz2 = writepathtable(cd, vdblock, Big);
147 	assert(sz == sz2);
148 	setpathtable(cd, vdblock, sz, lloc, bloc);
149 }
150 
151 void
writepathtables(Cdimg * cd)152 writepathtables(Cdimg *cd)
153 {
154 	cd->pathblock = cd->nextblock;
155 
156 	writepathtablepair(cd, cd->iso9660pvd);
157 	if(cd->flags & CDjoliet)
158 		writepathtablepair(cd, cd->jolietsvd);
159 }
160