]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/9660/path.c
merge
[plan9front.git] / sys / src / cmd / disk / 9660 / path.c
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, i, *len, n;
90         uvlong start, end, rdoff;
91         Cdir *c;
92         Cpath p;
93
94         Creadblock(cd, buf, vdblock, Blocksize);
95         c = (Cdir*)(buf + offsetof(Cvoldesc, rootdir[0]));
96
97         rp = 0;
98         wp = 0;
99         len = nil;
100         start = (vlong)cd->nextblock * Blocksize;
101         Cwseek(cd, start);
102         Crseek(cd, start);
103         writepath(cd, c, 1, size);
104         len = addlength(len, little(c->dlen, 4), wp);
105         wp++;
106
107         while(rp < wp) {
108                 Crdpath(cd, &p);
109                 n = (len[rp]+Blocksize-1)/Blocksize;
110                 rp++;
111                 bk = (size==Big ? big : little)(p.dloc, 4);
112                 rdoff = Croffset(cd);
113                 for(i=0; i<n; i++) {
114                         Creadblock(cd, buf, bk+i, Blocksize);
115                         c = (Cdir*)buf;
116                         if(i != 0 && c->namelen == 1 && c->name[0] == '\0')
117                                 break;  /* hit another directory; stop */
118                         while(c->len && c->namelen &&
119                             (uchar*)c + c->len < buf + Blocksize) {
120                                 if(c->flags & 0x02 &&
121                                     (c->namelen > 1 || c->name[0] > '\001')) {
122                                         /* directory */
123                                         writepath(cd, c, rp, size);
124                                         len = addlength(len, little(c->dlen, 4), wp);
125                                         wp++;
126                                 }
127                                 c = (Cdir*)((uchar*)c+c->len);
128                         }
129                 }
130                 Crseek(cd, rdoff);
131         }
132         end = Cwoffset(cd);
133         Cpadblock(cd);
134         return end-start;
135 }
136
137
138 static void
139 writepathtablepair(Cdimg *cd, ulong vdblock)
140 {
141         ulong bloc, lloc, sz, sz2;
142
143         lloc = cd->nextblock;
144         sz = writepathtable(cd, vdblock, Little);
145         bloc = cd->nextblock;
146         sz2 = writepathtable(cd, vdblock, Big);
147         assert(sz == sz2);
148         setpathtable(cd, vdblock, sz, lloc, bloc);
149 }
150
151 void
152 writepathtables(Cdimg *cd)
153 {
154         cd->pathblock = cd->nextblock;
155
156         writepathtablepair(cd, cd->iso9660pvd);
157         if(cd->flags & CDjoliet)
158                 writepathtablepair(cd, cd->jolietsvd);
159 }