plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }