156 lines
3.6 KiB
C
156 lines
3.6 KiB
C
|
|
#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);
|
||
|
|
}
|