path.c (3641B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <libsec.h> 5 6 #include "iso9660.h" 7 8 /* 9 * Add the requisite path tables to the CD image. 10 * They get put on the end once everything else is done. 11 * We use the path table itself as a queue in the breadth-first 12 * traversal of the tree. 13 * 14 * The only problem with this is that the path table does not 15 * store the lengths of the directories. So we keep an explicit 16 * map in an array in memory. 17 */ 18 19 enum { 20 Big, 21 Little 22 }; 23 24 static void 25 Crdpath(Cdimg *cd, Cpath *p) 26 { 27 p->namelen = Cgetc(cd); 28 if(p->namelen == 0) { 29 Crseek(cd, (Croffset(cd)+Blocksize-1)/Blocksize * Blocksize); 30 p->namelen = Cgetc(cd); 31 assert(p->namelen != 0); 32 } 33 34 p->xlen = Cgetc(cd); 35 assert(p->xlen == 0); /* sanity, might not be true if we start using the extended fields */ 36 37 Cread(cd, p->dloc, 4); 38 Cread(cd, p->parent, 2); 39 p->name[0] = '\0'; 40 Crseek(cd, Croffset(cd)+p->namelen+p->xlen+(p->namelen&1)); /* skip name, ext data */ 41 } 42 43 static void 44 writepath(Cdimg *cd, Cdir *c, int parent, int size) 45 { 46 /* 47 DO NOT UNCOMMENT THIS CODE. 48 This commented-out code is here only so that no one comes 49 along and adds it later. 50 51 The ISO 9660 spec is silent about whether path table entries 52 need to be padded so that they never cross block boundaries. 53 It would be reasonable to assume that they are like every other 54 data structure in the bloody spec; this code pads them out. 55 56 Empirically, though, they're NOT padded. Windows NT and 57 derivatives are the only known current operating systems 58 that actually read these things. 59 60 int l; 61 62 l = 1+1+4+2+c->namelen; 63 if(Cwoffset(cd)/Blocksize != (Cwoffset(cd)+l)/Blocksize) 64 Cpadblock(cd); 65 */ 66 Cputc(cd, c->namelen); 67 Cputc(cd, 0); 68 Cwrite(cd, c->dloc + (size==Little ? 0 : 4), 4); 69 (size==Little ? Cputnl : Cputnm)(cd, parent, 2); 70 Cwrite(cd, c->name, c->namelen); 71 if(c->namelen & 1) 72 Cputc(cd, 0); 73 } 74 75 static ulong* 76 addlength(ulong *a, ulong x, int n) 77 { 78 if(n%128==0) 79 a = erealloc(a, (n+128)*sizeof a[0]); 80 a[n] = x; 81 return a; 82 } 83 84 static ulong 85 writepathtable(Cdimg *cd, ulong vdblock, int size) 86 { 87 int rp, wp; 88 uchar buf[Blocksize]; 89 ulong bk, end, i, *len, n, rdoff, start; 90 Cdir *c; 91 Cpath p; 92 93 Creadblock(cd, buf, vdblock, Blocksize); 94 c = (Cdir*)(buf+offsetof(Cvoldesc, rootdir[0])); 95 96 rp = 0; 97 wp = 0; 98 len = nil; 99 start = cd->nextblock*Blocksize; 100 Cwseek(cd, start); 101 Crseek(cd, start); 102 writepath(cd, c, 1, size); 103 len = addlength(len, little(c->dlen, 4), wp); 104 wp++; 105 106 while(rp < wp) { 107 Crdpath(cd, &p); 108 n = (len[rp]+Blocksize-1)/Blocksize; 109 rp++; 110 bk = (size==Big ? big : little)(p.dloc, 4); 111 rdoff = Croffset(cd); 112 for(i=0; i<n; i++) { 113 Creadblock(cd, buf, bk+i, Blocksize); 114 c = (Cdir*)buf; 115 if(i != 0 && c->namelen == 1 && c->name[0] == '\0') /* hit another directory; stop */ 116 break; 117 while(c->len && c->namelen && (uchar*)c+c->len < buf+Blocksize) { 118 if((c->flags & 0x02) && (c->namelen > 1 || c->name[0] > '\001')) { /* directory */ 119 writepath(cd, c, rp, size); 120 len = addlength(len, little(c->dlen, 4), wp); 121 wp++; 122 } 123 c = (Cdir*)((uchar*)c+c->len); 124 } 125 } 126 Crseek(cd, rdoff); 127 } 128 end = Cwoffset(cd); 129 Cpadblock(cd); 130 return end-start; 131 } 132 133 134 static void 135 writepathtablepair(Cdimg *cd, ulong vdblock) 136 { 137 ulong bloc, lloc, sz, sz2; 138 139 lloc = cd->nextblock; 140 sz = writepathtable(cd, vdblock, Little); 141 bloc = cd->nextblock; 142 sz2 = writepathtable(cd, vdblock, Big); 143 assert(sz == sz2); 144 setpathtable(cd, vdblock, sz, lloc, bloc); 145 } 146 147 void 148 writepathtables(Cdimg *cd) 149 { 150 cd->pathblock = cd->nextblock; 151 152 writepathtablepair(cd, cd->iso9660pvd); 153 if(cd->flags & CDjoliet) 154 writepathtablepair(cd, cd->jolietsvd); 155 }