180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <bio.h>
480ee5cbfSDavid du Colombier #include <libsec.h>
580ee5cbfSDavid du Colombier
680ee5cbfSDavid du Colombier #include "iso9660.h"
780ee5cbfSDavid du Colombier
880ee5cbfSDavid du Colombier /*
980ee5cbfSDavid du Colombier * Add the requisite path tables to the CD image.
1080ee5cbfSDavid du Colombier * They get put on the end once everything else is done.
1180ee5cbfSDavid du Colombier * We use the path table itself as a queue in the breadth-first
1280ee5cbfSDavid du Colombier * traversal of the tree.
1380ee5cbfSDavid du Colombier *
1480ee5cbfSDavid du Colombier * The only problem with this is that the path table does not
1580ee5cbfSDavid du Colombier * store the lengths of the directories. So we keep an explicit
1680ee5cbfSDavid du Colombier * map in an array in memory.
1780ee5cbfSDavid du Colombier */
1880ee5cbfSDavid du Colombier
1980ee5cbfSDavid du Colombier enum {
2080ee5cbfSDavid du Colombier Big,
2180ee5cbfSDavid du Colombier Little
2280ee5cbfSDavid du Colombier };
2380ee5cbfSDavid du Colombier
2480ee5cbfSDavid du Colombier static void
Crdpath(Cdimg * cd,Cpath * p)2580ee5cbfSDavid du Colombier Crdpath(Cdimg *cd, Cpath *p)
2680ee5cbfSDavid du Colombier {
2780ee5cbfSDavid du Colombier p->namelen = Cgetc(cd);
2880ee5cbfSDavid du Colombier if(p->namelen == 0) {
2980ee5cbfSDavid du Colombier Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize);
3080ee5cbfSDavid du Colombier p->namelen = Cgetc(cd);
3180ee5cbfSDavid du Colombier assert(p->namelen != 0);
3280ee5cbfSDavid du Colombier }
3380ee5cbfSDavid du Colombier
3480ee5cbfSDavid du Colombier p->xlen = Cgetc(cd);
3580ee5cbfSDavid du Colombier assert(p->xlen == 0); /* sanity, might not be true if we start using the extended fields */
3680ee5cbfSDavid du Colombier
3780ee5cbfSDavid du Colombier Cread(cd, p->dloc, 4);
3880ee5cbfSDavid du Colombier Cread(cd, p->parent, 2);
3980ee5cbfSDavid du Colombier p->name[0] = '\0';
4080ee5cbfSDavid du Colombier Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1)); /* skip name, ext data */
4180ee5cbfSDavid du Colombier }
4280ee5cbfSDavid du Colombier
4380ee5cbfSDavid du Colombier static void
writepath(Cdimg * cd,Cdir * c,int parent,int size)4480ee5cbfSDavid du Colombier writepath(Cdimg *cd, Cdir *c, int parent, int size)
4580ee5cbfSDavid du Colombier {
465d459b5aSDavid du Colombier /*
475d459b5aSDavid du Colombier DO NOT UNCOMMENT THIS CODE.
485d459b5aSDavid du Colombier This commented-out code is here only so that no one comes
495d459b5aSDavid du Colombier along and adds it later.
505d459b5aSDavid du Colombier
515d459b5aSDavid du Colombier The ISO 9660 spec is silent about whether path table entries
525d459b5aSDavid du Colombier need to be padded so that they never cross block boundaries.
535d459b5aSDavid du Colombier It would be reasonable to assume that they are like every other
545d459b5aSDavid du Colombier data structure in the bloody spec; this code pads them out.
555d459b5aSDavid du Colombier
565d459b5aSDavid du Colombier Empirically, though, they're NOT padded. Windows NT and
575d459b5aSDavid du Colombier derivatives are the only known current operating systems
585d459b5aSDavid du Colombier that actually read these things.
595d459b5aSDavid du Colombier
6080ee5cbfSDavid du Colombier int l;
6180ee5cbfSDavid du Colombier
6280ee5cbfSDavid du Colombier l = 1+1+4+2+c->namelen;
6380ee5cbfSDavid du Colombier if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize)
6480ee5cbfSDavid du Colombier Cpadblock(cd);
655d459b5aSDavid du Colombier */
6680ee5cbfSDavid du Colombier Cputc(cd, c->namelen);
6780ee5cbfSDavid du Colombier Cputc(cd, 0);
6880ee5cbfSDavid du Colombier Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4);
6980ee5cbfSDavid du Colombier (size==Little ? Cputnl : Cputnm)(cd, parent, 2);
7080ee5cbfSDavid du Colombier Cwrite(cd, c->name, c->namelen);
7180ee5cbfSDavid du Colombier if(c->namelen & 1)
7280ee5cbfSDavid du Colombier Cputc(cd, 0);
7380ee5cbfSDavid du Colombier }
7480ee5cbfSDavid du Colombier
7580ee5cbfSDavid du Colombier static ulong*
addlength(ulong * a,ulong x,int n)7680ee5cbfSDavid du Colombier addlength(ulong *a, ulong x, int n)
7780ee5cbfSDavid du Colombier {
7880ee5cbfSDavid du Colombier if(n%128==0)
7980ee5cbfSDavid du Colombier a = erealloc(a, (n+128)*sizeof a[0]);
8080ee5cbfSDavid du Colombier a[n] = x;
8180ee5cbfSDavid du Colombier return a;
8280ee5cbfSDavid du Colombier }
8380ee5cbfSDavid du Colombier
8480ee5cbfSDavid du Colombier static ulong
writepathtable(Cdimg * cd,ulong vdblock,int size)8580ee5cbfSDavid du Colombier writepathtable(Cdimg *cd, ulong vdblock, int size)
8680ee5cbfSDavid du Colombier {
8780ee5cbfSDavid du Colombier int rp, wp;
8880ee5cbfSDavid du Colombier uchar buf[Blocksize];
89*73ee67a1SDavid du Colombier ulong bk, i, *len, n;
90*73ee67a1SDavid du Colombier uvlong start, end, rdoff;
9180ee5cbfSDavid du Colombier Cdir *c;
9280ee5cbfSDavid du Colombier Cpath p;
9380ee5cbfSDavid du Colombier
9480ee5cbfSDavid du Colombier Creadblock(cd, buf, vdblock, Blocksize);
9580ee5cbfSDavid du Colombier c = (Cdir*)(buf + offsetof(Cvoldesc, rootdir[0]));
9680ee5cbfSDavid du Colombier
9780ee5cbfSDavid du Colombier rp = 0;
9880ee5cbfSDavid du Colombier wp = 0;
9980ee5cbfSDavid du Colombier len = nil;
100*73ee67a1SDavid du Colombier start = (vlong)cd->nextblock * Blocksize;
10180ee5cbfSDavid du Colombier Cwseek(cd, start);
10280ee5cbfSDavid du Colombier Crseek(cd, start);
10380ee5cbfSDavid du Colombier writepath(cd, c, 1, size);
10480ee5cbfSDavid du Colombier len = addlength(len, little(c->dlen, 4), wp);
10580ee5cbfSDavid du Colombier wp++;
10680ee5cbfSDavid du Colombier
10780ee5cbfSDavid du Colombier while(rp < wp) {
10880ee5cbfSDavid du Colombier Crdpath(cd, &p);
10980ee5cbfSDavid du Colombier n = (len[rp]+Blocksize-1)/Blocksize;
11080ee5cbfSDavid du Colombier rp++;
11180ee5cbfSDavid du Colombier bk = (size==Big ? big : little)(p.dloc, 4);
11280ee5cbfSDavid du Colombier rdoff = Croffset(cd);
11380ee5cbfSDavid du Colombier for(i=0; i<n; i++) {
11480ee5cbfSDavid du Colombier Creadblock(cd, buf, bk+i, Blocksize);
11580ee5cbfSDavid du Colombier c = (Cdir*)buf;
116*73ee67a1SDavid du Colombier if(i != 0 && c->namelen == 1 && c->name[0] == '\0')
117*73ee67a1SDavid du Colombier break; /* hit another directory; stop */
118*73ee67a1SDavid du Colombier while(c->len && c->namelen &&
119*73ee67a1SDavid du Colombier (uchar*)c + c->len < buf + Blocksize) {
120*73ee67a1SDavid du Colombier if(c->flags & 0x02 &&
121*73ee67a1SDavid du Colombier (c->namelen > 1 || c->name[0] > '\001')) {
122*73ee67a1SDavid du Colombier /* directory */
12380ee5cbfSDavid du Colombier writepath(cd, c, rp, size);
12480ee5cbfSDavid du Colombier len = addlength(len, little(c->dlen, 4), wp);
12580ee5cbfSDavid du Colombier wp++;
12680ee5cbfSDavid du Colombier }
12780ee5cbfSDavid du Colombier c = (Cdir*)((uchar*)c+c->len);
12880ee5cbfSDavid du Colombier }
12980ee5cbfSDavid du Colombier }
13080ee5cbfSDavid du Colombier Crseek(cd, rdoff);
13180ee5cbfSDavid du Colombier }
13280ee5cbfSDavid du Colombier end = Cwoffset(cd);
13380ee5cbfSDavid du Colombier Cpadblock(cd);
13480ee5cbfSDavid du Colombier return end-start;
13580ee5cbfSDavid du Colombier }
13680ee5cbfSDavid du Colombier
13780ee5cbfSDavid du Colombier
13880ee5cbfSDavid du Colombier static void
writepathtablepair(Cdimg * cd,ulong vdblock)13980ee5cbfSDavid du Colombier writepathtablepair(Cdimg *cd, ulong vdblock)
14080ee5cbfSDavid du Colombier {
14180ee5cbfSDavid du Colombier ulong bloc, lloc, sz, sz2;
14280ee5cbfSDavid du Colombier
14380ee5cbfSDavid du Colombier lloc = cd->nextblock;
14480ee5cbfSDavid du Colombier sz = writepathtable(cd, vdblock, Little);
14580ee5cbfSDavid du Colombier bloc = cd->nextblock;
14680ee5cbfSDavid du Colombier sz2 = writepathtable(cd, vdblock, Big);
14780ee5cbfSDavid du Colombier assert(sz == sz2);
14880ee5cbfSDavid du Colombier setpathtable(cd, vdblock, sz, lloc, bloc);
14980ee5cbfSDavid du Colombier }
15080ee5cbfSDavid du Colombier
15180ee5cbfSDavid du Colombier void
writepathtables(Cdimg * cd)15280ee5cbfSDavid du Colombier writepathtables(Cdimg *cd)
15380ee5cbfSDavid du Colombier {
15480ee5cbfSDavid du Colombier cd->pathblock = cd->nextblock;
15580ee5cbfSDavid du Colombier
15680ee5cbfSDavid du Colombier writepathtablepair(cd, cd->iso9660pvd);
15780ee5cbfSDavid du Colombier if(cd->flags & CDjoliet)
15880ee5cbfSDavid du Colombier writepathtablepair(cd, cd->jolietsvd);
15980ee5cbfSDavid du Colombier }
160