Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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*
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
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
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
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
}