#include #include #include #include #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) { 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; inamelen == 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); }