|  | #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); | 
|  | } |