aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9660/path.c
blob: f2757dba93f6ec5f6f325d0491b8cb64ce546434 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <libsec.h>

#include "iso9660.h"

/*
 * Add the requisite path tables to the CD image.
 * They get put on the end once everything else is done.
 * We use the path table itself as a queue in the breadth-first
 * traversal of the tree.  
 *
 * The only problem with this is that the path table does not
 * store the lengths of the directories.  So we keep an explicit
 * map in an array in memory.
 */

enum {
	Big,
	Little
};

static void
Crdpath(Cdimg *cd, Cpath *p)
{
	p->namelen = Cgetc(cd);
	if(p->namelen == 0) {
		Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize);
		p->namelen = Cgetc(cd);
		assert(p->namelen != 0);
	}

	p->xlen = Cgetc(cd);
	assert(p->xlen == 0);	/* sanity, might not be true if we start using the extended fields */

	Cread(cd, p->dloc, 4);
	Cread(cd, p->parent, 2);
	p->name[0] = '\0';
	Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1));	/* skip name, ext data */
}

static void
writepath(Cdimg *cd, Cdir *c, int parent, int size)
{
/*
	DO NOT UNCOMMENT THIS CODE.
	This commented-out code is here only so that no one comes
	along and adds it later.

	The ISO 9660 spec is silent about whether path table entries
	need to be padded so that they never cross block boundaries.
	It would be reasonable to assume that they are like every other
	data structure in the bloody spec; this code pads them out.

	Empirically, though, they're NOT padded.  Windows NT and
	derivatives are the only known current operating systems
	that actually read these things.

	int l;

	l = 1+1+4+2+c->namelen;
	if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize)
		Cpadblock(cd);
*/
	Cputc(cd, c->namelen);
	Cputc(cd, 0);
	Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4);
	(size==Little ? Cputnl : Cputnm)(cd, parent, 2);
	Cwrite(cd, c->name, c->namelen);
	if(c->namelen & 1)
		Cputc(cd, 0);
}

static ulong*
addlength(ulong *a, ulong x, int n)
{
	if(n%128==0)
		a = erealloc(a, (n+128)*sizeof a[0]);
	a[n] = x;
	return a;
}

static ulong
writepathtable(Cdimg *cd, ulong vdblock, int size)
{
	int rp, wp;
	uchar buf[Blocksize];
	ulong bk, end, i, *len, n, rdoff, start;
	Cdir *c;
	Cpath p;

	Creadblock(cd, buf, vdblock, Blocksize);
	c = (Cdir*)(buf+offsetof(Cvoldesc, rootdir[0]));

	rp = 0;
	wp = 0;
	len = nil;
	start = cd->nextblock*Blocksize;
	Cwseek(cd, start);
	Crseek(cd, start);
	writepath(cd, c, 1, size);
	len = addlength(len, little(c->dlen, 4), wp);
	wp++;

	while(rp < wp) {
		Crdpath(cd, &p);
		n = (len[rp]+Blocksize-1)/Blocksize;
		rp++;
		bk = (size==Big ? big : little)(p.dloc, 4);
		rdoff = Croffset(cd);
		for(i=0; i<n; i++) {
			Creadblock(cd, buf, bk+i, Blocksize);
			c = (Cdir*)buf;
			if(i != 0 && c->namelen == 1 && c->name[0] == '\0')	/* hit another directory; stop */
				break;
			while(c->len && c->namelen && (uchar*)c+c->len < buf+Blocksize) {
				if((c->flags & 0x02) && (c->namelen > 1 || c->name[0] > '\001')) {	/* directory */
					writepath(cd, c, rp, size);
					len = addlength(len, little(c->dlen, 4), wp);
					wp++;
				}
				c = (Cdir*)((uchar*)c+c->len);
			}
		}
		Crseek(cd, rdoff);
	}
	end = Cwoffset(cd);
	Cpadblock(cd);
	return end-start;
}


static void
writepathtablepair(Cdimg *cd, ulong vdblock)
{
	ulong bloc, lloc, sz, sz2;

	lloc = cd->nextblock;
	sz = writepathtable(cd, vdblock, Little);
	bloc = cd->nextblock;
	sz2 = writepathtable(cd, vdblock, Big);
	assert(sz == sz2);
	setpathtable(cd, vdblock, sz, lloc, bloc);
}

void
writepathtables(Cdimg *cd)
{
	cd->pathblock = cd->nextblock;

	writepathtablepair(cd, cd->iso9660pvd);
	if(cd->flags & CDjoliet)
		writepathtablepair(cd, cd->jolietsvd);
}