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